Skip to content

jcksber/logik-plug-contracts

Repository files navigation

logik-genesis-contracts

The Plug

Notes for completing The Plug (pre-production)

Notes for transitioning to Production

  • New Alchemy API key (production version)
  • Need to deploy using our shared wallet (not my personal MetaMask) - so update public/private keys
  • Need to setup hardhat.config.js for Ethereum mainnet
  • Switch logic from cycling the asset from every 2 hours to every 2 months

Post-production if anything

  • Potentially write a script that LOGIK can execute on his own to obtain the list of level owners so that I don't need to do it for him every time he wants an updated list
  • Script that can auto batch transfer the airdrops based on a list of addresses

Citizens of the World

Working on the assumption that all of these NFT's are basically unrelated unless viewed on LOGIK's website

Passport

  • Passport should have a mapping from owner addresses to stamp balances (bridged w/ the address for the collection), i.e.
  // Passport.sol
  // mapping from owner addresses to stamp balances (bridged w/ the address for the collection)
  mapping (address => mapping(address => uint32[]) 
  // e.g.
  // 0xEab64..Gz9 => [0x8a..er3 => [0,1,1,0,0,0,1], ...]
  // means owner 0xEa.. has collected stamps 1, 2, and 7 from the collection at address 0x8a..

!!!!!!(NOTE - 8.19.21) "The problem with this approach

This approach is tempting for its simplicity. But let's look at what happens if we later add a function to transfer a zombie from one owner to another (which we'll definitely want to add in a later lesson!).

That transfer function would need to:

Push the zombie to the new owner's ownerToZombies array,
Remove the zombie from the old owner's ownerToZombies array,
Shift every zombie in the older owner's array up one place to fill the hole, and then
Reduce the array length by 1.

" -> The point is transfering ownership of stamps becomes difficult WAIT MAYBE.... MY APPROACH MAY BE SLIGHTLY DIFFERENT

  • This means we need a function: awardStamp(address passportOwner, address stamp, uint256 stampId)

  • Maybe also: awardCitizen(address passportOwner, address citizen, uint256 citizenId)

  • Normal functions I can think of: beforeTransfer tokenURI (the cover of the passport will be different if you own a character???) mintPassport

  • Does anything change if you also mint a character??? Or is this just the first page of the passport if so????

Stamp Collection

  • This will communicate directly with Passport.sol in order to validate whether or not someone is allowed to mint a stamp
  • Each collection will be a new contract where NUM_PASSPORTS Stamps get minted
  • The URI returned should never change, but should at least be unique on IPFS (API can handle this)
  • Pretty sure these should be simple, while Passport is more complicated than I currently have documented...

Citizen

  • The main thing with the Citizens is some sort of hash function that determines the URI (because it will be a random, unique citizen determined by something like the minter's address)

  • The API will be doing the heavy lifting as far as the logic is concerned -> I think it needs to use the minter's address to assemble a Character (using layers) and then in-turn pin it to IPFS using Pinata's API, then pin a JSON file that corresponds to it, and then deliver that final IPFS hash back to the contract for the URI.

  • Maybe this also communicates with Passport.sol in order to "award" a Citizen

  • Create a CitizenFactory that has a function to randomly generate a 16 bit number to correspond to the citizen's features e.g.

    contract ZombieFactory {
    
      uint dnaDigits = 16;
      uint dnaModulus = 10 ** dnaDigits;
    
      struct Zombie {
          string name;
          uint dna;
      }
    
      Zombie[] public zombies;
    
      function _createZombie(string memory _name, uint _dna) private {
          zombies.push(Zombie(_name, _dna));
      }
    
      function _generateRandomDna(string memory _str) private view returns (uint) {
          uint rand = uint(keccak256(abi.encodePacked(_str)));
          return rand % dnaModulus;
      }
    
      function createRandomZombie(string memory _name) public {
          uint randDna = _generateRandomDna(_name);
          _createZombie(_name, randDna);
      }
    
    }

    Then with javascript:

      // Here's how we would access our contract:
      var abi = /* abi generated by the compiler */
      var ZombieFactoryContract = web3.eth.contract(abi)
      var contractAddress = /* our contract address on Ethereum after deploying */
      var ZombieFactory = ZombieFactoryContract.at(contractAddress)
      // `ZombieFactory` has access to our contract's public functions and events
    
      // some sort of event listener to take the text input:
      $("#ourButton").click(function(e) {
        var name = $("#nameInput").val()
        // Call our contract's `createRandomZombie` function:
        ZombieFactory.createRandomZombie(name)
      })
    
      // Listen for the `NewZombie` event, and update the UI
      var event = ZombieFactory.NewZombie(function(error, result) {
        if (error) return
        generateZombie(result.zombieId, result.name, result.dna)
      })
    
      // take the Zombie dna, and update our image
      function generateZombie(id, name, dna) {
        let dnaStr = String(dna)
        // pad DNA with leading zeroes if it's less than 16 characters
        while (dnaStr.length < 16)
          dnaStr = "0" + dnaStr
    
        let zombieDetails = {
          // first 2 digits make up the head. We have 7 possible heads, so % 7
          // to get a number 0 - 6, then add 1 to make it 1 - 7. Then we have 7
          // image files named "head1.png" through "head7.png" we load based on
          // this number:
          headChoice: dnaStr.substring(0, 2) % 7 + 1,
          // 2nd 2 digits make up the eyes, 11 variations:
          eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
          // 6 variations of shirts:
          shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
          // last 6 digits control color. Updated using CSS filter: hue-rotate
          // which has 360 degrees:
          skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
          eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
          clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
          zombieName: name,
          zombieDescription: "A Level 1 CryptoZombie",
        }
        return zombieDetails
      }

    Doing something with a zombie:

    function getZombieDetails(id) {
        return cryptoZombies.methods.zombies(id).call()
      }
    
      // Call the function and do something with the result:
      getZombieDetails(15)
      .then(function(result) {
        console.log("Zombie 15: " + JSON.stringify(result));
    });


8.21.21. -

- NOTE: the `_squad` variable may be improperly used right now since I have that 
  Gnosis wallet (or whatever) ... it's useful for testing that's for sure

- Kind of want to try refactoring even more to make `KasbeerMade721` to handle a bunch
  of the stuff I'd want done for every ERC721 i make...


8.23.21  -

- Refactored the code and am now testing it ... all of the ownership logic, 
  custom hash stuff, and erc721 overrides have been taken out of `Plug.sol` 
  in order to focus more on the code that matters for this particular NFT
  -> so far so good

- Opensea testnet sucks


8.24.21 - 

- My build environmnent was broken for a solid few hours,,,,,,,,,,,,:|

- Did some Zombie Truffle tutorials and that's why I got into intalling truffle and
  eveything went to shit

- This is all a massive headache 

- Okay i fixed all of the issues that somehow arose ... i don't rememeber exactly 
  what broke everything but `solc` was suddenly a problem and then upon re-installation 
  the versions for everything were fkd up

- Should have never added truffle....... hardhat already has testing abilities!!

- Removed truffle, added mocha (for hardhat)

- I think everything gets even cleaner with interfaces....


8.25.21 - 

- Lots of issues with tests...:
```
Plug contract
    Deployment
      ✓ Deployment should add my dev address to `_squad` (9436ms)
      ✓ Deployment should add logik's dev address to `_squad` (13428ms)
    Squad functionality
      1) Squad members should be addable
      2) Squad members should be removable
    Minting & burning
      3) Minting should increment the token id by 1 each time
      4) Minting should set the birthday of `tokenId` to the current time
      5) Burning should remove a token permnently
    Time-triggered asset cycling
      6) Plug should update it's hash every 60 days for the first year
      7) Plug should turn into an Alchemist after 4 years


  2 passing (3m)
  7 failing

  1) Plug contract
       Squad functionality
         Squad members should be addable:
     Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/test/Plug.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

  2) Plug contract
       Squad functionality
         Squad members should be removable:
     Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/test/Plug.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

  3) Plug contract
       Minting & burning
         Minting should increment the token id by 1 each time:
     Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/test/Plug.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

  4) Plug contract
       Minting & burning
         Minting should set the birthday of `tokenId` to the current time:
     Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/test/Plug.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

  5) Plug contract
       Minting & burning
         Burning should remove a token permnently:
     Error: invalid BigNumber value (argument="value", value={"hash":"0x7475821720995861e6a4361d312ad30d36e3eaeb89e027b61d05de3c4d6a2e89","type":2,"accessList":[],"blockHash":null,"blockNumber":null,"transactionIndex":null,"confirmations":0,"from":"0xEAb4Aea5cD7376C04923236c504e7e91362566D1","gasPrice":{"type":"BigNumber","hex":"0x3b9aca0b"},"maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x3b9aca00"},"maxFeePerGas":{"type":"BigNumber","hex":"0x3b9aca0b"},"gasLimit":{"type":"BigNumber","hex":"0x01c78b"},"to":"0x41e80cBcd4705AFfD5bA39A438169A147DFd65cE","value":{"type":"BigNumber","hex":"0x00"},"nonce":235,"data":"0x815a12f6000000000000000000000000eab4aea5cd7376c04923236c504e7e91362566d1","r":"0x232a494fe1673bdb8796e96d0bb2730ed5f1165782a47b5eaba6750917dfb732","s":"0x1f7e1d7f34175eabbc901c7a17c85260c2cfdb4b14867dc8cd724f2cdcfb6df8","v":0,"creates":null,"chainId":4}, code=INVALID_ARGUMENT, version=bignumber/5.4.1)
      at Logger.makeError (node_modules/@ethersproject/logger/src.ts/index.ts:213:28)
      at Logger.throwError (node_modules/@ethersproject/logger/src.ts/index.ts:225:20)
      at Logger.throwArgumentError (node_modules/@ethersproject/logger/src.ts/index.ts:229:21)
      at Function.BigNumber.from (node_modules/@ethersproject/bignumber/src.ts/bignumber.ts:291:23)
      at NumberCoder.encode (node_modules/@ethersproject/abi/src.ts/coders/number.ts:25:27)
      at /Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/node_modules/@ethersproject/abi/src.ts/coders/array.ts:71:19
      at Array.forEach (<anonymous>)
      at Object.pack (node_modules/@ethersproject/abi/src.ts/coders/array.ts:54:12)
      at TupleCoder.encode (node_modules/@ethersproject/abi/src.ts/coders/tuple.ts:54:16)
      at AbiCoder.encode (node_modules/@ethersproject/abi/src.ts/abi-coder.ts:112:15)
      at Interface._encodeParams (node_modules/@ethersproject/abi/src.ts/interface.ts:325:31)
      at Interface.encodeFunctionData (node_modules/@ethersproject/abi/src.ts/interface.ts:380:18)
      at /Users/kamikaze/Desktop/localsrc/crypto/logik-genesis-dapp/smart-contracts/node_modules/@ethersproject/contracts/src.ts/index.ts:212:37
      at step (node_modules/@ethersproject/contracts/lib/index.js:48:23)
      at Object.next (node_modules/@ethersproject/contracts/lib/index.js:29:53)
      at fulfilled (node_modules/@ethersproject/contracts/lib/index.js:20:58)

  6) Plug contract
       Time-triggered asset cycling
         Plug should update it's hash every 60 days for the first year:
     ReferenceError: web3 is not defined
      at Object.increase (test/helpers/time.js:4:5)
      at Context.<anonymous> (test/Plug.js:154:16)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (internal/process/task_queues.js:97:5)

  7) Plug contract
       Time-triggered asset cycling
         Plug should turn into an Alchemist after 4 years:
     ReferenceError: web3 is not defined
      at Object.increase (test/helpers/time.js:4:5)
      at Context.<anonymous> (test/Plug.js:174:15)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (internal/process/task_queues.js:97:5)
```

- So... to summarize
  1) Time-outs: Squad add, squad remove, mint increment, mint birthday
  2) invalid BigNumber value: burning token
  3) web3 is not defined: Asset cycling every 60 days, and 4 years


8.30.21 - 

- Today I'd like to: 
  (1) finish writing tests for every function associated 
      with the Plug, 
  (2) deploy a few to opensea testnet to see if the testnet was the 
      problem before or if it's related to the code, 
  (3) research how i'm going to deploy 
      to the mainnet & how much it will cost,
  (4) flatten the code for an audit & get a professional opinion on deployment

- Time traveling is turning out to be quite difficult in testing...
- I'm considering I just ignore this for the time being since I've seen 
  the time-dependent things happen on opensea first-hand


8.31.21 - 

- Semi-finished (1), opensea (2) is still seemingly broken and can't rely on it, 
  didn't quite get to (3), not how necessary flattening is for an audit;

  -> Need to just investigate `listLevelOwners` a little more thoroughly before 
     I can be confident in the contracts being ready for audit

- UPDATE: now we're making a website where the user mints the Plug for themself 
          (so opensea's problems aren't even a big deal really)
          NOTE!!: THIS MEANS `onlyOwner` on the `mint721` function is problematic
                  ANYONE should be able to mint a plug
- Tonight:
  (1) Investigate `listLevelOwners`
  (2) Create a shell website that we can easily start to customize for visual 
      purposes (the other site I started for the citizens of the world should
      essentially suffice, so just use the tutorial from Alchemy)











About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published