From 3f7df6baf5347b34ef321c52c3cb668d5c9372d8 Mon Sep 17 00:00:00 2001 From: Talitha Anderson Date: Fri, 1 Sep 2023 01:46:15 +0800 Subject: [PATCH] Refactor (#156) * feat: refactor grantOperatorPermissionsWithSig * feat: rename * feat: minor refactor with storageLib * feat: minor refactor with OperatorLib & PostLib * feat: minor refactor for LinkLib * feat: minor refactor * feat: use _handleHash * feat: use ValidationLib * feat: remove duplicated code * feat: optimize _validateCallerPermission & _validateCallerPermission4Note * Update Web3EntryBase.sol * chore: optimize code size * chore: minor refactor * feat: add test cases for grantOperatorPermissionsWithSig * feat: update test cases * feat: remove ProxyAdmin * feat: minor refactor * feat: minor refactor * feat: update test cases * feat: rename LinklistLogic as LinklistLib * feat: remove unused scripts * feat: fix for solhint * feat: fix compile * feat: update test cases for operators * feat: add testGrantOperatorPermissionsWithSigMultiple * feat: add deleteAttachedLinklistId to StorageLib * feat: add testInitialize * feat: add return value for collectTips4Character * feat: add testCollectTips4CharacterAfterEndTime * feat: removed unused functions for linklist * feat: update test cases * feat: update test cases for operators * feat: update test cases for linkAddress * feat: add test cases for linklist * feat: add test cases for linkCharacter & linkERC721 & linkLinklist * feat: add test cases for linkModule * feat: add test cases for linkNote &linkUri * feat: update test case for web3Entry & remove Web3EntryBase * feat: add testInitialize for web3Entry * feat: update deploy script * feat: update testCheckStorage --- .solhint.json | 1 + Makefile | 2 +- build-info/Linklist.json | 230 +--- contracts/Linklist.sol | 58 +- contracts/Web3Entry.sol | 866 ++++++++++++- contracts/Web3EntryBase.sol | 1089 ----------------- contracts/base/LinklistBase.sol | 57 +- contracts/interfaces/ILinklist.sol | 23 +- contracts/interfaces/ITipsWithConfig.sol | 5 +- contracts/interfaces/IWeb3Entry.sol | 24 +- .../{CharacterLogic.sol => CharacterLib.sol} | 79 +- contracts/libraries/DataTypes.sol | 2 + .../libraries/{LinkLogic.sol => LinkLib.sol} | 97 +- .../{LinklistLogic.sol => LinklistLib.sol} | 25 +- contracts/libraries/MetaTxLib.sol | 98 ++ .../{OperatorLogic.sol => OperatorLib.sol} | 39 +- .../libraries/{PostLogic.sol => PostLib.sol} | 88 +- contracts/libraries/StorageLib.sol | 143 +++ contracts/libraries/ValidationLib.sol | 50 + contracts/misc/TipsWithConfig.sol | 15 +- contracts/misc/TipsWithFee.sol | 2 +- contracts/mocks/ERC1271WalletMock.sol | 46 + contracts/mocks/NFT.sol | 2 +- contracts/modules/ModuleBase.sol | 1 + contracts/storage/Web3EntryStorage.sol | 11 - contracts/upgradeability/ProxyAdmin.sol | 91 -- scripts/UpgradeLinklist.sol | 22 - scripts/UpgradePeriphery.sol | 23 - scripts/UpgradeWeb3Entry.sol | 22 - scripts/deploy.ts | 43 +- scripts/deployWeb3Entry.ts | 43 +- scripts/upgradeLinklist.ts | 34 - scripts/upgradePeriphery.ts | 41 - scripts/upgradeWeb3Entry.ts | 65 - slither.db.json | 2 +- test/Characters/CharacterSettings.t.sol | 224 ++-- test/Characters/CreateCharacter.t.sol | 56 +- test/Characters/PrimaryCharacter.t.sol | 139 +-- test/{links => }/Linklist.t.sol | 124 +- test/Note.t.sol | 247 ++-- test/Operator.t.sol | 799 ++++++------ test/UpgradeLinklist.t.sol | 49 +- test/Web3Entry.t.sol | 66 +- test/helpers/CommonTest.sol | 47 +- test/helpers/ReinitializeWeb3Entry.sol | 12 - test/links/LinkAddresses.t.sol | 144 ++- test/links/LinkCharacter.t.sol | 301 +++-- test/links/LinkERC721.t.sol | 95 +- test/links/LinkLinklist.t.sol | 162 +-- test/links/LinkModule.t.sol | 180 ++- test/links/LinkNote.t.sol | 93 +- test/links/LinkUri.t.sol | 112 +- test/misc/NewbieVilla.t.sol | 23 + test/misc/Tips.t.sol | 15 + test/misc/TipsWithConfig.t.sol | 213 +++- test/misc/TipsWithFee.t.sol | 15 + test/upgradeWeb3Entry.t.sol | 328 +---- 57 files changed, 3476 insertions(+), 3407 deletions(-) delete mode 100644 contracts/Web3EntryBase.sol rename contracts/libraries/{CharacterLogic.sol => CharacterLib.sol} (52%) rename contracts/libraries/{LinkLogic.sol => LinkLib.sol} (80%) rename contracts/libraries/{LinklistLogic.sol => LinklistLib.sol} (65%) create mode 100644 contracts/libraries/MetaTxLib.sol rename contracts/libraries/{OperatorLogic.sol => OperatorLib.sol} (74%) rename contracts/libraries/{PostLogic.sol => PostLib.sol} (70%) create mode 100644 contracts/libraries/StorageLib.sol create mode 100644 contracts/libraries/ValidationLib.sol create mode 100644 contracts/mocks/ERC1271WalletMock.sol delete mode 100644 contracts/upgradeability/ProxyAdmin.sol delete mode 100644 scripts/UpgradeLinklist.sol delete mode 100644 scripts/UpgradePeriphery.sol delete mode 100644 scripts/UpgradeWeb3Entry.sol delete mode 100644 scripts/upgradeLinklist.ts delete mode 100644 scripts/upgradePeriphery.ts delete mode 100644 scripts/upgradeWeb3Entry.ts rename test/{links => }/Linklist.t.sol (80%) delete mode 100644 test/helpers/ReinitializeWeb3Entry.sol diff --git a/.solhint.json b/.solhint.json index 26069cc57..c39a661c5 100644 --- a/.solhint.json +++ b/.solhint.json @@ -10,6 +10,7 @@ "const-name-snakecase": "off", "constructor-syntax": "error", "contract-name-camelcase": "error", + "custom-errors": "off", "event-name-camelcase": "error", "function-max-lines": ["warn",50], "func-name-mixedcase": "error", diff --git a/Makefile b/Makefile index ea3d1afed..f2cb04bee 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ solhint :; solhint -f table "{contracts,test,scripts}/**/*.sol" # slither # to install slither, visit [https://github.com/crytic/slither] -slither :; slither . --fail-low --triage-mode +slither :; slither . --fail-low #--triage-mode # mythril mythril : diff --git a/build-info/Linklist.json b/build-info/Linklist.json index 131a49694..91ef560f2 100644 --- a/build-info/Linklist.json +++ b/build-info/Linklist.json @@ -18,56 +18,6 @@ "name": "ErrTokenNotExists", "type": "error" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -156,7 +106,7 @@ { "indexed": false, "internalType": "string", - "name": "newUri", + "name": "uri", "type": "string" } ], @@ -331,24 +281,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -419,25 +351,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -870,30 +783,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1068,75 +957,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1164,7 +984,7 @@ }, { "internalType": "string", - "name": "newUri", + "name": "uri", "type": "string" } ], @@ -1205,25 +1025,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -1236,33 +1037,10 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" } ], - "bytecode": "0x608060405234801561001057600080fd5b50612f2b806100206000396000f3fe608060405234801561001057600080fd5b50600436106103415760003560e01c80636352211e116101b8578063a22cb46511610104578063c87b56dd116100a2578063e985e9c51161007c578063e985e9c514610804578063ed386e6514610840578063ed6223cf14610853578063f61087f61461086657600080fd5b8063c87b56dd146107c3578063cf101ac2146106aa578063e64f2baa146107e457600080fd5b8063ba27f58d116100de578063ba27f58d14610777578063c1cd4f821461078a578063c5a5ed511461079d578063c70881c5146107b057600080fd5b8063a22cb4651461073e578063ac150a5414610751578063b88d4fde1461076457600080fd5b80637803f217116101715780639037c0f91161014b5780639037c0f9146106e357806395d89b411461070357806397ce7df61461070b5780639cc7f7081461071e57600080fd5b80637803f217146106aa578063782f08ae146106bd5780638fd6dc39146106d057600080fd5b80636352211e1461062b5780636c217e121461063e5780636d37d2741461065157806370a082311461066457806373fbe0121461067757806376bac0251461068a57600080fd5b80632ea24efc116102925780634aa7b87a116102305780635c369ec31161020a5780635c369ec3146105c55780635cb46be7146105e55780635e9f678b146105f85780635f799cc61461061857600080fd5b80634aa7b87a1461053d5780635440522b146105505780635956da73146105b257600080fd5b806342c1721f1161026c57806342c1721f146104aa57806348d1b16c146104bd578063493fa4dc146104d05780634a7906b9146104e457600080fd5b80632ea24efc1461047157806342842e0e1461048457806342966c681461049757600080fd5b8063081812fc116102ff57806318160ddd116102d957806318160ddd1461043057806321cb72271461043857806323b872dd1461044b578063288893d61461045e57600080fd5b8063081812fc146103df578063095ea7b31461040a5780631801fbe51461041d57600080fd5b8062fba0271461034657806301ffc9a71461036c5780630370a1611461038f578063040f7618146103a457806306fdde03146103b7578063077f224a146103cc575b600080fd5b6103596103543660046124df565b610879565b6040519081526020015b60405180910390f35b61037f61037a3660046124f8565b6108c1565b6040519015158152602001610363565b6103a261039d36600461253a565b610913565b005b6103a26103b2366004612572565b61098b565b6103bf610a0b565b60405161036391906125ee565b6103a26103da36600461264a565b610a9d565b6103f26103ed3660046124df565b610be6565b6040516001600160a01b039091168152602001610363565b6103a26104183660046126ce565b610c7b565b61035961042b3660046126fa565b610d90565b601e54610359565b6103a26104463660046126fa565b610e58565b6103a261045936600461271c565b610e9b565b6103a261046c3660046126fa565b610ec1565b61035961047f36600461253a565b610f04565b6103a261049236600461271c565b610fd2565b6103a26104a53660046124df565b610fed565b6103a26104b83660046127d8565b6110b2565b6103596104cb3660046124df565b611127565b6103596104de3660046124df565b50600090565b6105306104f23660046124df565b604080518082019091526000808252602082015250600090815260116020908152604091829020825180840190935280548352600101549082015290565b6040516103639190612833565b61035961054b3660046124df565b611175565b6105a561055e3660046124df565b604080518082019091526000808252602082015250600090815260106020908152604091829020825180840190935280546001600160a01b03168352600101549082015290565b604051610363919061284a565b6103a26105c036600461286a565b6111bc565b6105d86105d33660046124df565b6111ff565b604051610363919061289a565b6103596105f3366004612572565b611249565b61060b6106063660046124df565b611309565b60405161036391906128e7565b6103bf6106263660046124df565b61144c565b6103f26106393660046124df565b6114ee565b61035961064c3660046127d8565b6115a4565b61035961065f3660046124df565b61163f565b61035961067236600461293e565b611686565b6103a26106853660046126fa565b6117b4565b61069d6106983660046124df565b61184e565b604051610363919061295b565b6103596106b83660046124df565b611898565b6103a26106cb3660046127d8565b6118dc565b6103596106de3660046124df565b6119b4565b6106f66106f13660046124df565b6119fb565b6040516103639190612993565b6103bf611b3a565b6103596107193660046124df565b611b49565b61035961072c3660046124df565b6000908152601d602052604090205490565b6103a261074c3660046129e6565b611b90565b6103bf61075f3660046124df565b611b9f565b6103a2610772366004612a19565b611c71565b61069d6107853660046124df565b611c9c565b6103a26107983660046126fa565b611ce6565b600a546103f2906001600160a01b031681565b6103a26107be3660046126fa565b611d29565b6103bf6107d13660046124df565b5060408051602081019091526000815290565b6107f76107f23660046124df565b611d6c565b6040516103639190612a99565b61037f610812366004612afb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6103a261084e36600461286a565b611eff565b61069d6108613660046124df565b611f42565b6103596108743660046124df565b611f8c565b6000818152601c6020526040812054829082036108a9576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604090205491505b50919050565b60006001600160e01b031982166380ac58cd60e01b14806108f257506001600160e01b03198216635b5e139f60e01b145b8061090d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600a546001600160a01b0316331461093e576040516302b6341b60e41b815260040160405180910390fd5b60008282604051602001610953929190612b29565b60408051601f1981840301815291815281516020928301206000878152601690935291209091506109849082611fd3565b5050505050565b600a546001600160a01b031633146109b6576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018390526044810182905260009060640160408051601f1981840301815291815281516020928301206000878152601790935291209091506109849082611fd3565b606060008054610a1a90612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4690612b5a565b8015610a935780601f10610a6857610100808354040283529160200191610a93565b820191906000526020600020905b815481529060010190602001808311610a7657829003601f168201915b5050505050905090565b601a54600290610100900460ff16158015610abf5750601a5460ff8083169116105b610b275760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b601a805461ffff191660ff831617610100179055600a80546001600160a01b0384166001600160a01b0319909116179055601b54601e55610b6a86868686611fdf565b6040514281527fcfdec2ffedf2f5ec02de6f351c5f9b6150601f657926e9e87b16390d562af4e79060200160405180910390a1601a805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6000818152600260205260408120546001600160a01b0316610c5f5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b1e565b506000908152600460205260409020546001600160a01b031690565b6000610c8682612030565b9050806001600160a01b0316836001600160a01b031603610cf35760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610b1e565b336001600160a01b0382161480610d0f5750610d0f8133610812565b610d815760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b1e565b610d8b83836120a7565b505050565b600a546000906001600160a01b03163314610dbe576040516302b6341b60e41b815260040160405180910390fd5b601b60008154610dcd90612ba4565b91829055506000818152600b60209081526040808320869055601c8252808320879055868352601d9091528120805492935090610e0983612ba4565b9091555050601e8054906000610e1e83612ba4565b9091555050604051819084906000907f7fa9aafeb8bb803d77de5d84bc2f2edbd842ca91b20cd5020aa21dfe26ab0be9908290a492915050565b600a546001600160a01b03163314610e83576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610d8b9082611fd3565b610ea53382612115565b610d8b5760405162461bcd60e51b8152600401610b1e90612bbd565b600a546001600160a01b03163314610eec576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610d8b908261220c565b600a546000906001600160a01b03163314610f32576040516302b6341b60e41b815260040160405180910390fd5b60008383604051602001610f47929190612b29565b60405160208183030381529060405280519060200120905084600014610f81576000858152601660205260409020610f7f908261220c565b505b6040805180820182526001600160a01b0380871682526020808301878152600086815260109092529390209151825491166001600160a01b0319909116178155905160019091015590509392505050565b610d8b83838360405180602001604052806000815250611c71565b600a546001600160a01b03163314611018576040516302b6341b60e41b815260040160405180910390fd5b6000818152601c602052604081205490819003611048576040516366012df560e11b815260040160405180910390fd5b6000818152601d602090815260408083208054600019908101909155601e80549091019055848352600b8252808320839055601c90915280822082905551839183917f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb69190a35050565b600a546001600160a01b031633146110dd576040516302b6341b60e41b815260040160405180910390fd5b6000816040516020016110f09190612c0e565b60408051601f1981840301815291815281516020928301206000868152601990935291209091506111219082611fd3565b50505050565b6000818152601c602052604081205482908203611157576040516366012df560e11b815260040160405180910390fd5b6000838152600c6020526040902061116e90612218565b9392505050565b6000818152601c6020526040812054829082036111a5576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040902061116e90612218565b600a546001600160a01b031633146111e7576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610d8b9082612222565b6000818152601c602052604081205460609183919003611232576040516366012df560e11b815260040160405180910390fd5b6000838152600d6020526040902061116e90612237565b600a546000906001600160a01b03163314611277576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b60208201526024810184905260448101839052600090606401604051602081830303815290604052805190602001209050846000146112d55760008581526017602052604090206112d3908261220c565b505b6040805180820182529485526020808601948552600083815260119091522093518455915160019093019290925592915050565b6000818152601c60205260408120546060918391900361133c576040516366012df560e11b815260040160405180910390fd5b600083815260176020526040812061135390612237565b9050805167ffffffffffffffff81111561136f5761136f61274c565b6040519080825280602002602001820160405280156113b457816020015b604080518082019091526000808252602082015281526020019060019003908161138d5790505b50925060005b81518110156114445760008282815181106113d7576113d7612c3c565b60200260200101519050601160008281526020019081526020016000206040518060400160405290816000820154815260200160018201548152505085838151811061142557611425612c3c565b602002602001018190525050808061143c90612ba4565b9150506113ba565b505050919050565b600081815260136020526040902080546060919061146990612b5a565b80601f016020809104026020016040519081016040528092919081815260200182805461149590612b5a565b80156114e25780601f106114b7576101008083540402835291602001916114e2565b820191906000526020600020905b8154815290600101906020018083116114c557829003601f168201915b50505050509050919050565b6000818152601c60205260408120548290820361151e576040516366012df560e11b815260040160405180910390fd5b6000838152601c602052604080822054600a5491516331a9108f60e11b8152600481018290529092916001600160a01b031690636352211e90602401602060405180830381865afa158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b9190612c52565b95945050505050565b600a546000906001600160a01b031633146115d2576040516302b6341b60e41b815260040160405180910390fd5b6000826040516020016115e59190612c0e565b6040516020818303038152906040528051906020012090508360001461161f57600084815260196020526040902061161d908261220c565b505b60008181526013602052604090206116378482612cbd565b509392505050565b6000818152601c60205260408120548290820361166f576040516366012df560e11b815260040160405180910390fd5b600083815260166020526040902061116e90612218565b600a546040516370a0823160e01b81526001600160a01b03838116600483015260009283929116906370a0823190602401602060405180830381865afa1580156116d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f89190612d7d565b905060005b818110156117ad57600a54604051632f745c5960e01b81526001600160a01b038681166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b9190612d7d565b6000818152601d60205260409020549091506117979085612d96565b93505080806117a590612ba4565b9150506116fd565b5050919050565b600a546001600160a01b031633146117df576040516302b6341b60e41b815260040160405180910390fd5b6000828152601c602052604081205483910361180e576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604080822084905551839185917ff0aea9f7b630d17e54614f5667704230d832f3c25c0ebbbd2cd7b52914ce11aa9190a3505050565b6000818152601c602052604081205460609183919003611881576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040902061116e90612237565b6000818152601c6020526040812054829082036118c8576040516366012df560e11b815260040160405180910390fd5b50506000908152601c602052604090205490565b6000828152601c602052604081205483910361190b576040516366012df560e11b815260040160405180910390fd5b600a546001600160a01b03163314801590611940575061192a836114ee565b6001600160a01b0316336001600160a01b031614155b1561195e57604051631a64ce6560e11b815260040160405180910390fd5b60008381526015602052604090206119768382612cbd565b50827f6d10c59cedadc720a2e20f54f0a461ef82bd35f762430e32ef049dd6d7fc2730836040516119a791906125ee565b60405180910390a2505050565b6000818152601c6020526040812054829082036119e4576040516366012df560e11b815260040160405180910390fd5b6000838152600e6020526040902061116e90612218565b6000818152601c602052604081205460609183919003611a2e576040516366012df560e11b815260040160405180910390fd5b6000838152601660205260408120611a4590612237565b9050805167ffffffffffffffff811115611a6157611a6161274c565b604051908082528060200260200182016040528015611aa657816020015b6040805180820190915260008082526020820152815260200190600190039081611a7f5790505b50925060005b8151811015611444576000828281518110611ac957611ac9612c3c565b602090810291909101810151600081815260108352604090819020815180830190925280546001600160a01b0316825260010154928101929092528651909250869084908110611b1b57611b1b612c3c565b6020026020010181905250508080611b3290612ba4565b915050611aac565b606060018054610a1a90612b5a565b6000818152601c602052604081205482908203611b79576040516366012df560e11b815260040160405180910390fd5b6000838152600d6020526040902061116e90612218565b611b9b338383612244565b5050565b6000818152601c602052604081205460609183919003611bd2576040516366012df560e11b815260040160405180910390fd5b60008381526015602052604090208054611beb90612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611c1790612b5a565b8015611c645780601f10611c3957610100808354040283529160200191611c64565b820191906000526020600020905b815481529060010190602001808311611c4757829003601f168201915b5050505050915050919050565b611c7b3383612115565b611c975760405162461bcd60e51b8152600401610b1e90612bbd565b611121565b6000818152601c602052604081205460609183919003611ccf576040516366012df560e11b815260040160405180910390fd5b6000838152600c6020526040902061116e90612237565b600a546001600160a01b03163314611d11576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610d8b908261220c565b600a546001600160a01b03163314611d54576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610d8b9082611fd3565b6000818152601c602052604081205460609183919003611d9f576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260408120611db690612237565b9050805167ffffffffffffffff811115611dd257611dd261274c565b604051908082528060200260200182016040528015611e0557816020015b6060815260200190600190039081611df05790505b50925060005b8151811015611444576000828281518110611e2857611e28612c3c565b60200260200101519050601360008281526020019081526020016000208054611e5090612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611e7c90612b5a565b8015611ec95780601f10611e9e57610100808354040283529160200191611ec9565b820191906000526020600020905b815481529060010190602001808311611eac57829003601f168201915b5050505050858381518110611ee057611ee0612c3c565b6020026020010181905250508080611ef790612ba4565b915050611e0b565b600a546001600160a01b03163314611f2a576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610d8b9082612312565b6000818152601c602052604081205460609183919003611f75576040516366012df560e11b815260040160405180910390fd5b6000838152600e6020526040902061116e90612237565b6000818152601c602052604081205482908203611fbc576040516366012df560e11b815260040160405180910390fd5b600083815260176020526040902061116e90612218565b600061116e8383612327565b611feb8484848461241a565b7f414cd0b34676984f09a5f76ce9718d4062e50283abe0e7e274a9a5b4e0c99c308484848442604051612022959493929190612dd2565b60405180910390a150505050565b6000818152600260205260408120546001600160a01b03168061090d5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610b1e565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906120dc82612030565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b031661218e5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b1e565b600061219983612030565b9050806001600160a01b0316846001600160a01b031614806121d45750836001600160a01b03166121c984610be6565b6001600160a01b0316145b8061220457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b600061116e8383612435565b600061090d825490565b600061116e836001600160a01b038416612327565b6060600061116e83612484565b816001600160a01b0316836001600160a01b0316036122a55760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b1e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b600061116e836001600160a01b038416612435565b6000818152600183016020526040812054801561241057600061234b600183612e0c565b855490915060009061235f90600190612e0c565b90508181146123c457600086600001828154811061237f5761237f612c3c565b90600052602060002001549050808760000184815481106123a2576123a2612c3c565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123d5576123d5612e1f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061090d565b600091505061090d565b6000612427848683612e35565b506001610984828483612e35565b600081815260018301602052604081205461247c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561090d565b50600061090d565b6060816000018054806020026020016040519081016040528092919081815260200182805480156114e257602002820191906000526020600020905b8154815260200190600101908083116124c05750505050509050919050565b6000602082840312156124f157600080fd5b5035919050565b60006020828403121561250a57600080fd5b81356001600160e01b03198116811461116e57600080fd5b6001600160a01b038116811461253757600080fd5b50565b60008060006060848603121561254f57600080fd5b83359250602084013561256181612522565b929592945050506040919091013590565b60008060006060848603121561258757600080fd5b505081359360208301359350604090920135919050565b60005b838110156125b95781810151838201526020016125a1565b50506000910152565b600081518084526125da81602086016020860161259e565b601f01601f19169290920160200192915050565b60208152600061116e60208301846125c2565b60008083601f84011261261357600080fd5b50813567ffffffffffffffff81111561262b57600080fd5b60208301915083602082850101111561264357600080fd5b9250929050565b60008060008060006060868803121561266257600080fd5b853567ffffffffffffffff8082111561267a57600080fd5b61268689838a01612601565b9097509550602088013591508082111561269f57600080fd5b506126ac88828901612601565b90945092505060408601356126c081612522565b809150509295509295909350565b600080604083850312156126e157600080fd5b82356126ec81612522565b946020939093013593505050565b6000806040838503121561270d57600080fd5b50508035926020909101359150565b60008060006060848603121561273157600080fd5b833561273c81612522565b9250602084013561256181612522565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561277d5761277d61274c565b604051601f8501601f19908116603f011681019082821181831017156127a5576127a561274c565b816040528093508581528686860111156127be57600080fd5b858560208301376000602087830101525050509392505050565b600080604083850312156127eb57600080fd5b82359150602083013567ffffffffffffffff81111561280957600080fd5b8301601f8101851361281a57600080fd5b61282985823560208401612762565b9150509250929050565b81518152602080830151908201526040810161090d565b81516001600160a01b03168152602080830151908201526040810161090d565b6000806040838503121561287d57600080fd5b82359150602083013561288f81612522565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156128db5783516001600160a01b0316835292840192918401916001016128b6565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156129315761292184835180518252602090810151910152565b9284019290850190600101612904565b5091979650505050505050565b60006020828403121561295057600080fd5b813561116e81612522565b6020808252825182820181905260009190848201906040850190845b818110156128db57835183529284019291840191600101612977565b602080825282518282018190526000919060409081850190868401855b82811015612931576129d684835180516001600160a01b03168252602090810151910152565b92840192908501906001016129b0565b600080604083850312156129f957600080fd5b8235612a0481612522565b91506020830135801515811461288f57600080fd5b60008060008060808587031215612a2f57600080fd5b8435612a3a81612522565b93506020850135612a4a81612522565b925060408501359150606085013567ffffffffffffffff811115612a6d57600080fd5b8501601f81018713612a7e57600080fd5b612a8d87823560208401612762565b91505092959194509250565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612aee57603f19888603018452612adc8583516125c2565b94509285019290850190600101612ac0565b5092979650505050505050565b60008060408385031215612b0e57600080fd5b8235612b1981612522565b9150602083013561288f81612522565b6545524337323160d01b815260609290921b6bffffffffffffffffffffffff19166006830152601a820152603a0190565b600181811c90821680612b6e57607f821691505b6020821081036108bb57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612bb657612bb6612b8e565b5060010190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b65416e7955726960d01b815260008251612c2f81600685016020870161259e565b9190910160060192915050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612c6457600080fd5b815161116e81612522565b601f821115610d8b57600081815260208120601f850160051c81016020861015612c965750805b601f850160051c820191505b81811015612cb557828155600101612ca2565b505050505050565b815167ffffffffffffffff811115612cd757612cd761274c565b612ceb81612ce58454612b5a565b84612c6f565b602080601f831160018114612d205760008415612d085750858301515b600019600386901b1c1916600185901b178555612cb5565b600085815260208120601f198616915b82811015612d4f57888601518255948401946001909101908401612d30565b5085821015612d6d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215612d8f57600080fd5b5051919050565b8082018082111561090d5761090d612b8e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000612de6606083018789612da9565b8281036020840152612df9818688612da9565b9150508260408301529695505050505050565b8181038181111561090d5761090d612b8e565b634e487b7160e01b600052603160045260246000fd5b67ffffffffffffffff831115612e4d57612e4d61274c565b612e6183612e5b8354612b5a565b83612c6f565b6000601f841160018114612e955760008515612e7d5750838201355b600019600387901b1c1916600186901b178355610984565b600083815260209020601f19861690835b82811015612ec65786850135825560209485019460019092019101612ea6565b5086821015612ee35760001960f88860031b161c19848701351681555b505060018560011b018355505050505056fea26469706673582212208e905ea7ff20ffead18b0c53cc8d184e92cce2650a616e85bebe7c18fecc32f264736f6c63430008120033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103415760003560e01c80636352211e116101b8578063a22cb46511610104578063c87b56dd116100a2578063e985e9c51161007c578063e985e9c514610804578063ed386e6514610840578063ed6223cf14610853578063f61087f61461086657600080fd5b8063c87b56dd146107c3578063cf101ac2146106aa578063e64f2baa146107e457600080fd5b8063ba27f58d116100de578063ba27f58d14610777578063c1cd4f821461078a578063c5a5ed511461079d578063c70881c5146107b057600080fd5b8063a22cb4651461073e578063ac150a5414610751578063b88d4fde1461076457600080fd5b80637803f217116101715780639037c0f91161014b5780639037c0f9146106e357806395d89b411461070357806397ce7df61461070b5780639cc7f7081461071e57600080fd5b80637803f217146106aa578063782f08ae146106bd5780638fd6dc39146106d057600080fd5b80636352211e1461062b5780636c217e121461063e5780636d37d2741461065157806370a082311461066457806373fbe0121461067757806376bac0251461068a57600080fd5b80632ea24efc116102925780634aa7b87a116102305780635c369ec31161020a5780635c369ec3146105c55780635cb46be7146105e55780635e9f678b146105f85780635f799cc61461061857600080fd5b80634aa7b87a1461053d5780635440522b146105505780635956da73146105b257600080fd5b806342c1721f1161026c57806342c1721f146104aa57806348d1b16c146104bd578063493fa4dc146104d05780634a7906b9146104e457600080fd5b80632ea24efc1461047157806342842e0e1461048457806342966c681461049757600080fd5b8063081812fc116102ff57806318160ddd116102d957806318160ddd1461043057806321cb72271461043857806323b872dd1461044b578063288893d61461045e57600080fd5b8063081812fc146103df578063095ea7b31461040a5780631801fbe51461041d57600080fd5b8062fba0271461034657806301ffc9a71461036c5780630370a1611461038f578063040f7618146103a457806306fdde03146103b7578063077f224a146103cc575b600080fd5b6103596103543660046124df565b610879565b6040519081526020015b60405180910390f35b61037f61037a3660046124f8565b6108c1565b6040519015158152602001610363565b6103a261039d36600461253a565b610913565b005b6103a26103b2366004612572565b61098b565b6103bf610a0b565b60405161036391906125ee565b6103a26103da36600461264a565b610a9d565b6103f26103ed3660046124df565b610be6565b6040516001600160a01b039091168152602001610363565b6103a26104183660046126ce565b610c7b565b61035961042b3660046126fa565b610d90565b601e54610359565b6103a26104463660046126fa565b610e58565b6103a261045936600461271c565b610e9b565b6103a261046c3660046126fa565b610ec1565b61035961047f36600461253a565b610f04565b6103a261049236600461271c565b610fd2565b6103a26104a53660046124df565b610fed565b6103a26104b83660046127d8565b6110b2565b6103596104cb3660046124df565b611127565b6103596104de3660046124df565b50600090565b6105306104f23660046124df565b604080518082019091526000808252602082015250600090815260116020908152604091829020825180840190935280548352600101549082015290565b6040516103639190612833565b61035961054b3660046124df565b611175565b6105a561055e3660046124df565b604080518082019091526000808252602082015250600090815260106020908152604091829020825180840190935280546001600160a01b03168352600101549082015290565b604051610363919061284a565b6103a26105c036600461286a565b6111bc565b6105d86105d33660046124df565b6111ff565b604051610363919061289a565b6103596105f3366004612572565b611249565b61060b6106063660046124df565b611309565b60405161036391906128e7565b6103bf6106263660046124df565b61144c565b6103f26106393660046124df565b6114ee565b61035961064c3660046127d8565b6115a4565b61035961065f3660046124df565b61163f565b61035961067236600461293e565b611686565b6103a26106853660046126fa565b6117b4565b61069d6106983660046124df565b61184e565b604051610363919061295b565b6103596106b83660046124df565b611898565b6103a26106cb3660046127d8565b6118dc565b6103596106de3660046124df565b6119b4565b6106f66106f13660046124df565b6119fb565b6040516103639190612993565b6103bf611b3a565b6103596107193660046124df565b611b49565b61035961072c3660046124df565b6000908152601d602052604090205490565b6103a261074c3660046129e6565b611b90565b6103bf61075f3660046124df565b611b9f565b6103a2610772366004612a19565b611c71565b61069d6107853660046124df565b611c9c565b6103a26107983660046126fa565b611ce6565b600a546103f2906001600160a01b031681565b6103a26107be3660046126fa565b611d29565b6103bf6107d13660046124df565b5060408051602081019091526000815290565b6107f76107f23660046124df565b611d6c565b6040516103639190612a99565b61037f610812366004612afb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6103a261084e36600461286a565b611eff565b61069d6108613660046124df565b611f42565b6103596108743660046124df565b611f8c565b6000818152601c6020526040812054829082036108a9576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604090205491505b50919050565b60006001600160e01b031982166380ac58cd60e01b14806108f257506001600160e01b03198216635b5e139f60e01b145b8061090d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600a546001600160a01b0316331461093e576040516302b6341b60e41b815260040160405180910390fd5b60008282604051602001610953929190612b29565b60408051601f1981840301815291815281516020928301206000878152601690935291209091506109849082611fd3565b5050505050565b600a546001600160a01b031633146109b6576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018390526044810182905260009060640160408051601f1981840301815291815281516020928301206000878152601790935291209091506109849082611fd3565b606060008054610a1a90612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4690612b5a565b8015610a935780601f10610a6857610100808354040283529160200191610a93565b820191906000526020600020905b815481529060010190602001808311610a7657829003601f168201915b5050505050905090565b601a54600290610100900460ff16158015610abf5750601a5460ff8083169116105b610b275760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b601a805461ffff191660ff831617610100179055600a80546001600160a01b0384166001600160a01b0319909116179055601b54601e55610b6a86868686611fdf565b6040514281527fcfdec2ffedf2f5ec02de6f351c5f9b6150601f657926e9e87b16390d562af4e79060200160405180910390a1601a805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6000818152600260205260408120546001600160a01b0316610c5f5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b1e565b506000908152600460205260409020546001600160a01b031690565b6000610c8682612030565b9050806001600160a01b0316836001600160a01b031603610cf35760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610b1e565b336001600160a01b0382161480610d0f5750610d0f8133610812565b610d815760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b1e565b610d8b83836120a7565b505050565b600a546000906001600160a01b03163314610dbe576040516302b6341b60e41b815260040160405180910390fd5b601b60008154610dcd90612ba4565b91829055506000818152600b60209081526040808320869055601c8252808320879055868352601d9091528120805492935090610e0983612ba4565b9091555050601e8054906000610e1e83612ba4565b9091555050604051819084906000907f7fa9aafeb8bb803d77de5d84bc2f2edbd842ca91b20cd5020aa21dfe26ab0be9908290a492915050565b600a546001600160a01b03163314610e83576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610d8b9082611fd3565b610ea53382612115565b610d8b5760405162461bcd60e51b8152600401610b1e90612bbd565b600a546001600160a01b03163314610eec576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610d8b908261220c565b600a546000906001600160a01b03163314610f32576040516302b6341b60e41b815260040160405180910390fd5b60008383604051602001610f47929190612b29565b60405160208183030381529060405280519060200120905084600014610f81576000858152601660205260409020610f7f908261220c565b505b6040805180820182526001600160a01b0380871682526020808301878152600086815260109092529390209151825491166001600160a01b0319909116178155905160019091015590509392505050565b610d8b83838360405180602001604052806000815250611c71565b600a546001600160a01b03163314611018576040516302b6341b60e41b815260040160405180910390fd5b6000818152601c602052604081205490819003611048576040516366012df560e11b815260040160405180910390fd5b6000818152601d602090815260408083208054600019908101909155601e80549091019055848352600b8252808320839055601c90915280822082905551839183917f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb69190a35050565b600a546001600160a01b031633146110dd576040516302b6341b60e41b815260040160405180910390fd5b6000816040516020016110f09190612c0e565b60408051601f1981840301815291815281516020928301206000868152601990935291209091506111219082611fd3565b50505050565b6000818152601c602052604081205482908203611157576040516366012df560e11b815260040160405180910390fd5b6000838152600c6020526040902061116e90612218565b9392505050565b6000818152601c6020526040812054829082036111a5576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040902061116e90612218565b600a546001600160a01b031633146111e7576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610d8b9082612222565b6000818152601c602052604081205460609183919003611232576040516366012df560e11b815260040160405180910390fd5b6000838152600d6020526040902061116e90612237565b600a546000906001600160a01b03163314611277576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b60208201526024810184905260448101839052600090606401604051602081830303815290604052805190602001209050846000146112d55760008581526017602052604090206112d3908261220c565b505b6040805180820182529485526020808601948552600083815260119091522093518455915160019093019290925592915050565b6000818152601c60205260408120546060918391900361133c576040516366012df560e11b815260040160405180910390fd5b600083815260176020526040812061135390612237565b9050805167ffffffffffffffff81111561136f5761136f61274c565b6040519080825280602002602001820160405280156113b457816020015b604080518082019091526000808252602082015281526020019060019003908161138d5790505b50925060005b81518110156114445760008282815181106113d7576113d7612c3c565b60200260200101519050601160008281526020019081526020016000206040518060400160405290816000820154815260200160018201548152505085838151811061142557611425612c3c565b602002602001018190525050808061143c90612ba4565b9150506113ba565b505050919050565b600081815260136020526040902080546060919061146990612b5a565b80601f016020809104026020016040519081016040528092919081815260200182805461149590612b5a565b80156114e25780601f106114b7576101008083540402835291602001916114e2565b820191906000526020600020905b8154815290600101906020018083116114c557829003601f168201915b50505050509050919050565b6000818152601c60205260408120548290820361151e576040516366012df560e11b815260040160405180910390fd5b6000838152601c602052604080822054600a5491516331a9108f60e11b8152600481018290529092916001600160a01b031690636352211e90602401602060405180830381865afa158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b9190612c52565b95945050505050565b600a546000906001600160a01b031633146115d2576040516302b6341b60e41b815260040160405180910390fd5b6000826040516020016115e59190612c0e565b6040516020818303038152906040528051906020012090508360001461161f57600084815260196020526040902061161d908261220c565b505b60008181526013602052604090206116378482612cbd565b509392505050565b6000818152601c60205260408120548290820361166f576040516366012df560e11b815260040160405180910390fd5b600083815260166020526040902061116e90612218565b600a546040516370a0823160e01b81526001600160a01b03838116600483015260009283929116906370a0823190602401602060405180830381865afa1580156116d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f89190612d7d565b905060005b818110156117ad57600a54604051632f745c5960e01b81526001600160a01b038681166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b9190612d7d565b6000818152601d60205260409020549091506117979085612d96565b93505080806117a590612ba4565b9150506116fd565b5050919050565b600a546001600160a01b031633146117df576040516302b6341b60e41b815260040160405180910390fd5b6000828152601c602052604081205483910361180e576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604080822084905551839185917ff0aea9f7b630d17e54614f5667704230d832f3c25c0ebbbd2cd7b52914ce11aa9190a3505050565b6000818152601c602052604081205460609183919003611881576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040902061116e90612237565b6000818152601c6020526040812054829082036118c8576040516366012df560e11b815260040160405180910390fd5b50506000908152601c602052604090205490565b6000828152601c602052604081205483910361190b576040516366012df560e11b815260040160405180910390fd5b600a546001600160a01b03163314801590611940575061192a836114ee565b6001600160a01b0316336001600160a01b031614155b1561195e57604051631a64ce6560e11b815260040160405180910390fd5b60008381526015602052604090206119768382612cbd565b50827f6d10c59cedadc720a2e20f54f0a461ef82bd35f762430e32ef049dd6d7fc2730836040516119a791906125ee565b60405180910390a2505050565b6000818152601c6020526040812054829082036119e4576040516366012df560e11b815260040160405180910390fd5b6000838152600e6020526040902061116e90612218565b6000818152601c602052604081205460609183919003611a2e576040516366012df560e11b815260040160405180910390fd5b6000838152601660205260408120611a4590612237565b9050805167ffffffffffffffff811115611a6157611a6161274c565b604051908082528060200260200182016040528015611aa657816020015b6040805180820190915260008082526020820152815260200190600190039081611a7f5790505b50925060005b8151811015611444576000828281518110611ac957611ac9612c3c565b602090810291909101810151600081815260108352604090819020815180830190925280546001600160a01b0316825260010154928101929092528651909250869084908110611b1b57611b1b612c3c565b6020026020010181905250508080611b3290612ba4565b915050611aac565b606060018054610a1a90612b5a565b6000818152601c602052604081205482908203611b79576040516366012df560e11b815260040160405180910390fd5b6000838152600d6020526040902061116e90612218565b611b9b338383612244565b5050565b6000818152601c602052604081205460609183919003611bd2576040516366012df560e11b815260040160405180910390fd5b60008381526015602052604090208054611beb90612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611c1790612b5a565b8015611c645780601f10611c3957610100808354040283529160200191611c64565b820191906000526020600020905b815481529060010190602001808311611c4757829003601f168201915b5050505050915050919050565b611c7b3383612115565b611c975760405162461bcd60e51b8152600401610b1e90612bbd565b611121565b6000818152601c602052604081205460609183919003611ccf576040516366012df560e11b815260040160405180910390fd5b6000838152600c6020526040902061116e90612237565b600a546001600160a01b03163314611d11576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610d8b908261220c565b600a546001600160a01b03163314611d54576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610d8b9082611fd3565b6000818152601c602052604081205460609183919003611d9f576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260408120611db690612237565b9050805167ffffffffffffffff811115611dd257611dd261274c565b604051908082528060200260200182016040528015611e0557816020015b6060815260200190600190039081611df05790505b50925060005b8151811015611444576000828281518110611e2857611e28612c3c565b60200260200101519050601360008281526020019081526020016000208054611e5090612b5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611e7c90612b5a565b8015611ec95780601f10611e9e57610100808354040283529160200191611ec9565b820191906000526020600020905b815481529060010190602001808311611eac57829003601f168201915b5050505050858381518110611ee057611ee0612c3c565b6020026020010181905250508080611ef790612ba4565b915050611e0b565b600a546001600160a01b03163314611f2a576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610d8b9082612312565b6000818152601c602052604081205460609183919003611f75576040516366012df560e11b815260040160405180910390fd5b6000838152600e6020526040902061116e90612237565b6000818152601c602052604081205482908203611fbc576040516366012df560e11b815260040160405180910390fd5b600083815260176020526040902061116e90612218565b600061116e8383612327565b611feb8484848461241a565b7f414cd0b34676984f09a5f76ce9718d4062e50283abe0e7e274a9a5b4e0c99c308484848442604051612022959493929190612dd2565b60405180910390a150505050565b6000818152600260205260408120546001600160a01b03168061090d5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610b1e565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906120dc82612030565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b031661218e5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b1e565b600061219983612030565b9050806001600160a01b0316846001600160a01b031614806121d45750836001600160a01b03166121c984610be6565b6001600160a01b0316145b8061220457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b600061116e8383612435565b600061090d825490565b600061116e836001600160a01b038416612327565b6060600061116e83612484565b816001600160a01b0316836001600160a01b0316036122a55760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b1e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b600061116e836001600160a01b038416612435565b6000818152600183016020526040812054801561241057600061234b600183612e0c565b855490915060009061235f90600190612e0c565b90508181146123c457600086600001828154811061237f5761237f612c3c565b90600052602060002001549050808760000184815481106123a2576123a2612c3c565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123d5576123d5612e1f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061090d565b600091505061090d565b6000612427848683612e35565b506001610984828483612e35565b600081815260018301602052604081205461247c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561090d565b50600061090d565b6060816000018054806020026020016040519081016040528092919081815260200182805480156114e257602002820191906000526020600020905b8154815260200190600101908083116124c05750505050509050919050565b6000602082840312156124f157600080fd5b5035919050565b60006020828403121561250a57600080fd5b81356001600160e01b03198116811461116e57600080fd5b6001600160a01b038116811461253757600080fd5b50565b60008060006060848603121561254f57600080fd5b83359250602084013561256181612522565b929592945050506040919091013590565b60008060006060848603121561258757600080fd5b505081359360208301359350604090920135919050565b60005b838110156125b95781810151838201526020016125a1565b50506000910152565b600081518084526125da81602086016020860161259e565b601f01601f19169290920160200192915050565b60208152600061116e60208301846125c2565b60008083601f84011261261357600080fd5b50813567ffffffffffffffff81111561262b57600080fd5b60208301915083602082850101111561264357600080fd5b9250929050565b60008060008060006060868803121561266257600080fd5b853567ffffffffffffffff8082111561267a57600080fd5b61268689838a01612601565b9097509550602088013591508082111561269f57600080fd5b506126ac88828901612601565b90945092505060408601356126c081612522565b809150509295509295909350565b600080604083850312156126e157600080fd5b82356126ec81612522565b946020939093013593505050565b6000806040838503121561270d57600080fd5b50508035926020909101359150565b60008060006060848603121561273157600080fd5b833561273c81612522565b9250602084013561256181612522565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561277d5761277d61274c565b604051601f8501601f19908116603f011681019082821181831017156127a5576127a561274c565b816040528093508581528686860111156127be57600080fd5b858560208301376000602087830101525050509392505050565b600080604083850312156127eb57600080fd5b82359150602083013567ffffffffffffffff81111561280957600080fd5b8301601f8101851361281a57600080fd5b61282985823560208401612762565b9150509250929050565b81518152602080830151908201526040810161090d565b81516001600160a01b03168152602080830151908201526040810161090d565b6000806040838503121561287d57600080fd5b82359150602083013561288f81612522565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156128db5783516001600160a01b0316835292840192918401916001016128b6565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156129315761292184835180518252602090810151910152565b9284019290850190600101612904565b5091979650505050505050565b60006020828403121561295057600080fd5b813561116e81612522565b6020808252825182820181905260009190848201906040850190845b818110156128db57835183529284019291840191600101612977565b602080825282518282018190526000919060409081850190868401855b82811015612931576129d684835180516001600160a01b03168252602090810151910152565b92840192908501906001016129b0565b600080604083850312156129f957600080fd5b8235612a0481612522565b91506020830135801515811461288f57600080fd5b60008060008060808587031215612a2f57600080fd5b8435612a3a81612522565b93506020850135612a4a81612522565b925060408501359150606085013567ffffffffffffffff811115612a6d57600080fd5b8501601f81018713612a7e57600080fd5b612a8d87823560208401612762565b91505092959194509250565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612aee57603f19888603018452612adc8583516125c2565b94509285019290850190600101612ac0565b5092979650505050505050565b60008060408385031215612b0e57600080fd5b8235612b1981612522565b9150602083013561288f81612522565b6545524337323160d01b815260609290921b6bffffffffffffffffffffffff19166006830152601a820152603a0190565b600181811c90821680612b6e57607f821691505b6020821081036108bb57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612bb657612bb6612b8e565b5060010190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b65416e7955726960d01b815260008251612c2f81600685016020870161259e565b9190910160060192915050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612c6457600080fd5b815161116e81612522565b601f821115610d8b57600081815260208120601f850160051c81016020861015612c965750805b601f850160051c820191505b81811015612cb557828155600101612ca2565b505050505050565b815167ffffffffffffffff811115612cd757612cd761274c565b612ceb81612ce58454612b5a565b84612c6f565b602080601f831160018114612d205760008415612d085750858301515b600019600386901b1c1916600185901b178555612cb5565b600085815260208120601f198616915b82811015612d4f57888601518255948401946001909101908401612d30565b5085821015612d6d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215612d8f57600080fd5b5051919050565b8082018082111561090d5761090d612b8e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000612de6606083018789612da9565b8281036020840152612df9818688612da9565b9150508260408301529695505050505050565b8181038181111561090d5761090d612b8e565b634e487b7160e01b600052603160045260246000fd5b67ffffffffffffffff831115612e4d57612e4d61274c565b612e6183612e5b8354612b5a565b83612c6f565b6000601f841160018114612e955760008515612e7d5750838201355b600019600387901b1c1916600186901b178355610984565b600083815260209020601f19861690835b82811015612ec65786850135825560209485019460019092019101612ea6565b5086821015612ee35760001960f88860031b161c19848701351681555b505060018560011b018355505050505056fea26469706673582212208e905ea7ff20ffead18b0c53cc8d184e92cce2650a616e85bebe7c18fecc32f264736f6c63430008120033", + "bytecode": "0x608060405234801561001057600080fd5b50612729806100206000396000f3fe608060405234801561001057600080fd5b50600436106102895760003560e01c80636352211e1161015c57806397ce7df6116100ce578063c70881c511610087578063c70881c514610686578063cf101ac2146105a6578063e64f2baa14610699578063ed386e65146106b9578063ed6223cf146106cc578063f61087f6146106df57600080fd5b806397ce7df6146106075780639cc7f7081461061a578063ac150a541461063a578063ba27f58d1461064d578063c1cd4f8214610660578063c5a5ed511461067357600080fd5b806376bac0251161012057806376bac025146105865780637803f217146105a6578063782f08ae146105b95780638fd6dc39146105cc5780639037c0f9146105df57806395d89b41146105ff57600080fd5b80636352211e1461050f5780636c217e121461053a5780636d37d2741461054d57806370a082311461056057806373fbe0121461057357600080fd5b806342966c68116102005780635440522b116101b95780635440522b146104345780635956da73146104965780635c369ec3146104a95780635cb46be7146104c95780635e9f678b146104dc5780635f799cc6146104fc57600080fd5b806342966c681461037b57806342c1721f1461038e57806348d1b16c146103a1578063493fa4dc146103b45780634a7906b9146103c85780634aa7b87a1461042157600080fd5b8063077f224a11610252578063077f224a146103145780631801fbe51461032757806318160ddd1461033a57806321cb722714610342578063288893d6146103555780632ea24efc1461036857600080fd5b8062fba0271461028e57806301ffc9a7146102b45780630370a161146102d7578063040f7618146102ec57806306fdde03146102ff575b600080fd5b6102a161029c366004611e81565b6106f2565b6040519081526020015b60405180910390f35b6102c76102c2366004611e9a565b61073a565b60405190151581526020016102ab565b6102ea6102e5366004611edc565b61078c565b005b6102ea6102fa366004611f14565b610804565b610307610884565b6040516102ab9190611f90565b6102ea610322366004611fec565b610916565b6102a1610335366004612070565b610a5e565b601e546102a1565b6102ea610350366004612070565b610b26565b6102ea610363366004612070565b610b6e565b6102a1610376366004611edc565b610bb1565b6102ea610389366004611e81565b610c7f565b6102ea61039c3660046120a8565b610d44565b6102a16103af366004611e81565b610db9565b6102a16103c2366004611e81565b50600090565b6104146103d6366004611e81565b604080518082019091526000808252602082015250600090815260116020908152604091829020825180840190935280548352600101549082015290565b6040516102ab9190612163565b6102a161042f366004611e81565b610e07565b610489610442366004611e81565b604080518082019091526000808252602082015250600090815260106020908152604091829020825180840190935280546001600160a01b03168352600101549082015290565b6040516102ab919061217a565b6102ea6104a436600461219a565b610e4e565b6104bc6104b7366004611e81565b610e91565b6040516102ab91906121ca565b6102a16104d7366004611f14565b610edb565b6104ef6104ea366004611e81565b610f9b565b6040516102ab9190612217565b61030761050a366004611e81565b6110de565b61052261051d366004611e81565b611180565b6040516001600160a01b0390911681526020016102ab565b6102a16105483660046120a8565b6111b9565b6102a161055b366004611e81565b611254565b6102a161056e36600461226e565b61129b565b6102ea610581366004612070565b6113c9565b610599610594366004611e81565b611463565b6040516102ab919061228b565b6102a16105b4366004611e81565b6114ad565b6102ea6105c73660046120a8565b6114f1565b6102a16105da366004611e81565b6115c9565b6105f26105ed366004611e81565b611610565b6040516102ab91906122c3565b61030761174f565b6102a1610615366004611e81565b61175e565b6102a1610628366004611e81565b6000908152601d602052604090205490565b610307610648366004611e81565b6117a5565b61059961065b366004611e81565b611877565b6102ea61066e366004612070565b6118c1565b600a54610522906001600160a01b031681565b6102ea610694366004612070565b611904565b6106ac6106a7366004611e81565b611947565b6040516102ab9190612316565b6102ea6106c736600461219a565b611ada565b6105996106da366004611e81565b611b1d565b6102a16106ed366004611e81565b611b67565b6000818152601c602052604081205482908203610722576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604090205491505b50919050565b60006001600160e01b031982166380ac58cd60e01b148061076b57506001600160e01b03198216635b5e139f60e01b145b8061078657506301ffc9a760e01b6001600160e01b03198316145b92915050565b600a546001600160a01b031633146107b7576040516302b6341b60e41b815260040160405180910390fd5b600082826040516020016107cc929190612378565b60408051601f1981840301815291815281516020928301206000878152601690935291209091506107fd9082611bae565b5050505050565b600a546001600160a01b0316331461082f576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018390526044810182905260009060640160408051601f1981840301815291815281516020928301206000878152601790935291209091506107fd9082611bae565b606060008054610893906123a9565b80601f01602080910402602001604051908101604052809291908181526020018280546108bf906123a9565b801561090c5780601f106108e15761010080835404028352916020019161090c565b820191906000526020600020905b8154815290600101906020018083116108ef57829003601f168201915b5050505050905090565b601a54600290610100900460ff161580156109385750601a5460ff8083169116105b61099f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b601a805461ffff191660ff831617610100179055600a80546001600160a01b0384166001600160a01b0319909116179055601b54601e556109e286868686611bba565b6040514281527fcfdec2ffedf2f5ec02de6f351c5f9b6150601f657926e9e87b16390d562af4e79060200160405180910390a1601a805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b600a546000906001600160a01b03163314610a8c576040516302b6341b60e41b815260040160405180910390fd5b601b60008154610a9b906123f3565b91829055506000818152600b60209081526040808320869055601c8252808320879055868352601d9091528120805492935090610ad7836123f3565b9091555050601e8054906000610aec836123f3565b9091555050604051819084906000907f7fa9aafeb8bb803d77de5d84bc2f2edbd842ca91b20cd5020aa21dfe26ab0be9908290a492915050565b600a546001600160a01b03163314610b51576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610b699082611bae565b505050565b600a546001600160a01b03163314610b99576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610b699082611c1b565b600a546000906001600160a01b03163314610bdf576040516302b6341b60e41b815260040160405180910390fd5b60008383604051602001610bf4929190612378565b60405160208183030381529060405280519060200120905084600014610c2e576000858152601660205260409020610c2c9082611c1b565b505b6040805180820182526001600160a01b0380871682526020808301878152600086815260109092529390209151825491166001600160a01b0319909116178155905160019091015590509392505050565b600a546001600160a01b03163314610caa576040516302b6341b60e41b815260040160405180910390fd5b6000818152601c602052604081205490819003610cda576040516366012df560e11b815260040160405180910390fd5b6000818152601d602090815260408083208054600019908101909155601e80549091019055848352600b8252808320839055601c90915280822082905551839183917f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb69190a35050565b600a546001600160a01b03163314610d6f576040516302b6341b60e41b815260040160405180910390fd5b600081604051602001610d82919061240c565b60408051601f198184030181529181528151602092830120600086815260199093529120909150610db39082611bae565b50505050565b6000818152601c602052604081205482908203610de9576040516366012df560e11b815260040160405180910390fd5b6000838152600c60205260409020610e0090611c27565b9392505050565b6000818152601c602052604081205482908203610e37576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260409020610e0090611c27565b600a546001600160a01b03163314610e79576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610b699082611c31565b6000818152601c602052604081205460609183919003610ec4576040516366012df560e11b815260040160405180910390fd5b6000838152600d60205260409020610e0090611c46565b600a546000906001600160a01b03163314610f09576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018490526044810183905260009060640160405160208183030381529060405280519060200120905084600014610f67576000858152601760205260409020610f659082611c1b565b505b6040805180820182529485526020808601948552600083815260119091522093518455915160019093019290925592915050565b6000818152601c602052604081205460609183919003610fce576040516366012df560e11b815260040160405180910390fd5b6000838152601760205260408120610fe590611c46565b9050805167ffffffffffffffff81111561100157611001612092565b60405190808252806020026020018201604052801561104657816020015b604080518082019091526000808252602082015281526020019060019003908161101f5790505b50925060005b81518110156110d65760008282815181106110695761106961243a565b6020026020010151905060116000828152602001908152602001600020604051806040016040529081600082015481526020016001820154815250508583815181106110b7576110b761243a565b60200260200101819052505080806110ce906123f3565b91505061104c565b505050919050565b60008181526013602052604090208054606091906110fb906123a9565b80601f0160208091040260200160405190810160405280929190818152602001828054611127906123a9565b80156111745780601f1061114957610100808354040283529160200191611174565b820191906000526020600020905b81548152906001019060200180831161115757829003601f168201915b50505050509050919050565b6000818152601c6020526040812054829082036111b0576040516366012df560e11b815260040160405180910390fd5b610e0083611c53565b600a546000906001600160a01b031633146111e7576040516302b6341b60e41b815260040160405180910390fd5b6000826040516020016111fa919061240c565b604051602081830303815290604052805190602001209050836000146112345760008481526019602052604090206112329082611c1b565b505b600081815260136020526040902061124c848261249e565b509392505050565b6000818152601c602052604081205482908203611284576040516366012df560e11b815260040160405180910390fd5b6000838152601660205260409020610e0090611c27565b600a546040516370a0823160e01b81526001600160a01b03838116600483015260009283929116906370a0823190602401602060405180830381865afa1580156112e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130d919061255e565b905060005b818110156113c257600a54604051632f745c5960e01b81526001600160a01b038681166004830152602482018490526000921690632f745c5990604401602060405180830381865afa15801561136c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611390919061255e565b6000818152601d60205260409020549091506113ac9085612577565b93505080806113ba906123f3565b915050611312565b5050919050565b600a546001600160a01b031633146113f4576040516302b6341b60e41b815260040160405180910390fd5b6000828152601c6020526040812054839103611423576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604080822084905551839185917ff0aea9f7b630d17e54614f5667704230d832f3c25c0ebbbd2cd7b52914ce11aa9190a3505050565b6000818152601c602052604081205460609183919003611496576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260409020610e0090611c46565b6000818152601c6020526040812054829082036114dd576040516366012df560e11b815260040160405180910390fd5b50506000908152601c602052604090205490565b6000828152601c6020526040812054839103611520576040516366012df560e11b815260040160405180910390fd5b600a546001600160a01b03163314801590611555575061153f83611c53565b6001600160a01b0316336001600160a01b031614155b1561157357604051631a64ce6560e11b815260040160405180910390fd5b600083815260156020526040902061158b838261249e565b50827f6d10c59cedadc720a2e20f54f0a461ef82bd35f762430e32ef049dd6d7fc2730836040516115bc9190611f90565b60405180910390a2505050565b6000818152601c6020526040812054829082036115f9576040516366012df560e11b815260040160405180910390fd5b6000838152600e60205260409020610e0090611c27565b6000818152601c602052604081205460609183919003611643576040516366012df560e11b815260040160405180910390fd5b600083815260166020526040812061165a90611c46565b9050805167ffffffffffffffff81111561167657611676612092565b6040519080825280602002602001820160405280156116bb57816020015b60408051808201909152600080825260208201528152602001906001900390816116945790505b50925060005b81518110156110d65760008282815181106116de576116de61243a565b602090810291909101810151600081815260108352604090819020815180830190925280546001600160a01b03168252600101549281019290925286519092508690849081106117305761173061243a565b6020026020010181905250508080611747906123f3565b9150506116c1565b606060018054610893906123a9565b6000818152601c60205260408120548290820361178e576040516366012df560e11b815260040160405180910390fd5b6000838152600d60205260409020610e0090611c27565b6000818152601c6020526040812054606091839190036117d8576040516366012df560e11b815260040160405180910390fd5b600083815260156020526040902080546117f1906123a9565b80601f016020809104026020016040519081016040528092919081815260200182805461181d906123a9565b801561186a5780601f1061183f5761010080835404028352916020019161186a565b820191906000526020600020905b81548152906001019060200180831161184d57829003601f168201915b5050505050915050919050565b6000818152601c6020526040812054606091839190036118aa576040516366012df560e11b815260040160405180910390fd5b6000838152600c60205260409020610e0090611c46565b600a546001600160a01b031633146118ec576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610b699082611c1b565b600a546001600160a01b0316331461192f576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610b699082611bae565b6000818152601c60205260408120546060918391900361197a576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040812061199190611c46565b9050805167ffffffffffffffff8111156119ad576119ad612092565b6040519080825280602002602001820160405280156119e057816020015b60608152602001906001900390816119cb5790505b50925060005b81518110156110d6576000828281518110611a0357611a0361243a565b60200260200101519050601360008281526020019081526020016000208054611a2b906123a9565b80601f0160208091040260200160405190810160405280929190818152602001828054611a57906123a9565b8015611aa45780601f10611a7957610100808354040283529160200191611aa4565b820191906000526020600020905b815481529060010190602001808311611a8757829003601f168201915b5050505050858381518110611abb57611abb61243a565b6020026020010181905250508080611ad2906123f3565b9150506119e6565b600a546001600160a01b03163314611b05576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610b699082611ccf565b6000818152601c602052604081205460609183919003611b50576040516366012df560e11b815260040160405180910390fd5b6000838152600e60205260409020610e0090611c46565b6000818152601c602052604081205482908203611b97576040516366012df560e11b815260040160405180910390fd5b6000838152601760205260409020610e0090611c27565b6000610e008383611ce4565b6000611bc784868361258a565b506001611bd582848361258a565b507f414cd0b34676984f09a5f76ce9718d4062e50283abe0e7e274a9a5b4e0c99c308484848442604051611c0d959493929190612673565b60405180910390a150505050565b6000610e008383611dd7565b6000610786825490565b6000610e00836001600160a01b038416611ce4565b60606000610e0083611e26565b6000818152601c602052604080822054600a5491516331a9108f60e11b81526004810182905290916001600160a01b031690636352211e90602401602060405180830381865afa158015611cab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0091906126ad565b6000610e00836001600160a01b038416611dd7565b60008181526001830160205260408120548015611dcd576000611d086001836126ca565b8554909150600090611d1c906001906126ca565b9050818114611d81576000866000018281548110611d3c57611d3c61243a565b9060005260206000200154905080876000018481548110611d5f57611d5f61243a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611d9257611d926126dd565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610786565b6000915050610786565b6000818152600183016020526040812054611e1e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610786565b506000610786565b60608160000180548060200260200160405190810160405280929190818152602001828054801561117457602002820191906000526020600020905b815481526020019060010190808311611e625750505050509050919050565b600060208284031215611e9357600080fd5b5035919050565b600060208284031215611eac57600080fd5b81356001600160e01b031981168114610e0057600080fd5b6001600160a01b0381168114611ed957600080fd5b50565b600080600060608486031215611ef157600080fd5b833592506020840135611f0381611ec4565b929592945050506040919091013590565b600080600060608486031215611f2957600080fd5b505081359360208301359350604090920135919050565b60005b83811015611f5b578181015183820152602001611f43565b50506000910152565b60008151808452611f7c816020860160208601611f40565b601f01601f19169290920160200192915050565b602081526000610e006020830184611f64565b60008083601f840112611fb557600080fd5b50813567ffffffffffffffff811115611fcd57600080fd5b602083019150836020828501011115611fe557600080fd5b9250929050565b60008060008060006060868803121561200457600080fd5b853567ffffffffffffffff8082111561201c57600080fd5b61202889838a01611fa3565b9097509550602088013591508082111561204157600080fd5b5061204e88828901611fa3565b909450925050604086013561206281611ec4565b809150509295509295909350565b6000806040838503121561208357600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156120bb57600080fd5b82359150602083013567ffffffffffffffff808211156120da57600080fd5b818501915085601f8301126120ee57600080fd5b81358181111561210057612100612092565b604051601f8201601f19908116603f0116810190838211818310171561212857612128612092565b8160405282815288602084870101111561214157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b815181526020808301519082015260408101610786565b81516001600160a01b031681526020808301519082015260408101610786565b600080604083850312156121ad57600080fd5b8235915060208301356121bf81611ec4565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561220b5783516001600160a01b0316835292840192918401916001016121e6565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156122615761225184835180518252602090810151910152565b9284019290850190600101612234565b5091979650505050505050565b60006020828403121561228057600080fd5b8135610e0081611ec4565b6020808252825182820181905260009190848201906040850190845b8181101561220b578351835292840192918401916001016122a7565b602080825282518282018190526000919060409081850190868401855b828110156122615761230684835180516001600160a01b03168252602090810151910152565b92840192908501906001016122e0565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561236b57603f19888603018452612359858351611f64565b9450928501929085019060010161233d565b5092979650505050505050565b6545524337323160d01b815260609290921b6bffffffffffffffffffffffff19166006830152601a820152603a0190565b600181811c908216806123bd57607f821691505b60208210810361073457634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612405576124056123dd565b5060010190565b65416e7955726960d01b81526000825161242d816006850160208701611f40565b9190910160060192915050565b634e487b7160e01b600052603260045260246000fd5b601f821115610b6957600081815260208120601f850160051c810160208610156124775750805b601f850160051c820191505b8181101561249657828155600101612483565b505050505050565b815167ffffffffffffffff8111156124b8576124b8612092565b6124cc816124c684546123a9565b84612450565b602080601f83116001811461250157600084156124e95750858301515b600019600386901b1c1916600185901b178555612496565b600085815260208120601f198616915b8281101561253057888601518255948401946001909101908401612511565b508582101561254e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561257057600080fd5b5051919050565b80820180821115610786576107866123dd565b67ffffffffffffffff8311156125a2576125a2612092565b6125b6836125b083546123a9565b83612450565b6000601f8411600181146125ea57600085156125d25750838201355b600019600387901b1c1916600186901b1783556107fd565b600083815260209020601f19861690835b8281101561261b57868501358255602094850194600190920191016125fb565b50868210156126385760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60608152600061268760608301878961264a565b828103602084015261269a81868861264a565b9150508260408301529695505050505050565b6000602082840312156126bf57600080fd5b8151610e0081611ec4565b81810381811115610786576107866123dd565b634e487b7160e01b600052603160045260246000fdfea264697066735822122061781f9ecc9ea6d4accc2f0c3bb1e8f3606ef155ed6129199faa66c6f075eddc64736f6c63430008120033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102895760003560e01c80636352211e1161015c57806397ce7df6116100ce578063c70881c511610087578063c70881c514610686578063cf101ac2146105a6578063e64f2baa14610699578063ed386e65146106b9578063ed6223cf146106cc578063f61087f6146106df57600080fd5b806397ce7df6146106075780639cc7f7081461061a578063ac150a541461063a578063ba27f58d1461064d578063c1cd4f8214610660578063c5a5ed511461067357600080fd5b806376bac0251161012057806376bac025146105865780637803f217146105a6578063782f08ae146105b95780638fd6dc39146105cc5780639037c0f9146105df57806395d89b41146105ff57600080fd5b80636352211e1461050f5780636c217e121461053a5780636d37d2741461054d57806370a082311461056057806373fbe0121461057357600080fd5b806342966c68116102005780635440522b116101b95780635440522b146104345780635956da73146104965780635c369ec3146104a95780635cb46be7146104c95780635e9f678b146104dc5780635f799cc6146104fc57600080fd5b806342966c681461037b57806342c1721f1461038e57806348d1b16c146103a1578063493fa4dc146103b45780634a7906b9146103c85780634aa7b87a1461042157600080fd5b8063077f224a11610252578063077f224a146103145780631801fbe51461032757806318160ddd1461033a57806321cb722714610342578063288893d6146103555780632ea24efc1461036857600080fd5b8062fba0271461028e57806301ffc9a7146102b45780630370a161146102d7578063040f7618146102ec57806306fdde03146102ff575b600080fd5b6102a161029c366004611e81565b6106f2565b6040519081526020015b60405180910390f35b6102c76102c2366004611e9a565b61073a565b60405190151581526020016102ab565b6102ea6102e5366004611edc565b61078c565b005b6102ea6102fa366004611f14565b610804565b610307610884565b6040516102ab9190611f90565b6102ea610322366004611fec565b610916565b6102a1610335366004612070565b610a5e565b601e546102a1565b6102ea610350366004612070565b610b26565b6102ea610363366004612070565b610b6e565b6102a1610376366004611edc565b610bb1565b6102ea610389366004611e81565b610c7f565b6102ea61039c3660046120a8565b610d44565b6102a16103af366004611e81565b610db9565b6102a16103c2366004611e81565b50600090565b6104146103d6366004611e81565b604080518082019091526000808252602082015250600090815260116020908152604091829020825180840190935280548352600101549082015290565b6040516102ab9190612163565b6102a161042f366004611e81565b610e07565b610489610442366004611e81565b604080518082019091526000808252602082015250600090815260106020908152604091829020825180840190935280546001600160a01b03168352600101549082015290565b6040516102ab919061217a565b6102ea6104a436600461219a565b610e4e565b6104bc6104b7366004611e81565b610e91565b6040516102ab91906121ca565b6102a16104d7366004611f14565b610edb565b6104ef6104ea366004611e81565b610f9b565b6040516102ab9190612217565b61030761050a366004611e81565b6110de565b61052261051d366004611e81565b611180565b6040516001600160a01b0390911681526020016102ab565b6102a16105483660046120a8565b6111b9565b6102a161055b366004611e81565b611254565b6102a161056e36600461226e565b61129b565b6102ea610581366004612070565b6113c9565b610599610594366004611e81565b611463565b6040516102ab919061228b565b6102a16105b4366004611e81565b6114ad565b6102ea6105c73660046120a8565b6114f1565b6102a16105da366004611e81565b6115c9565b6105f26105ed366004611e81565b611610565b6040516102ab91906122c3565b61030761174f565b6102a1610615366004611e81565b61175e565b6102a1610628366004611e81565b6000908152601d602052604090205490565b610307610648366004611e81565b6117a5565b61059961065b366004611e81565b611877565b6102ea61066e366004612070565b6118c1565b600a54610522906001600160a01b031681565b6102ea610694366004612070565b611904565b6106ac6106a7366004611e81565b611947565b6040516102ab9190612316565b6102ea6106c736600461219a565b611ada565b6105996106da366004611e81565b611b1d565b6102a16106ed366004611e81565b611b67565b6000818152601c602052604081205482908203610722576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604090205491505b50919050565b60006001600160e01b031982166380ac58cd60e01b148061076b57506001600160e01b03198216635b5e139f60e01b145b8061078657506301ffc9a760e01b6001600160e01b03198316145b92915050565b600a546001600160a01b031633146107b7576040516302b6341b60e41b815260040160405180910390fd5b600082826040516020016107cc929190612378565b60408051601f1981840301815291815281516020928301206000878152601690935291209091506107fd9082611bae565b5050505050565b600a546001600160a01b0316331461082f576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018390526044810182905260009060640160408051601f1981840301815291815281516020928301206000878152601790935291209091506107fd9082611bae565b606060008054610893906123a9565b80601f01602080910402602001604051908101604052809291908181526020018280546108bf906123a9565b801561090c5780601f106108e15761010080835404028352916020019161090c565b820191906000526020600020905b8154815290600101906020018083116108ef57829003601f168201915b5050505050905090565b601a54600290610100900460ff161580156109385750601a5460ff8083169116105b61099f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b601a805461ffff191660ff831617610100179055600a80546001600160a01b0384166001600160a01b0319909116179055601b54601e556109e286868686611bba565b6040514281527fcfdec2ffedf2f5ec02de6f351c5f9b6150601f657926e9e87b16390d562af4e79060200160405180910390a1601a805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b600a546000906001600160a01b03163314610a8c576040516302b6341b60e41b815260040160405180910390fd5b601b60008154610a9b906123f3565b91829055506000818152600b60209081526040808320869055601c8252808320879055868352601d9091528120805492935090610ad7836123f3565b9091555050601e8054906000610aec836123f3565b9091555050604051819084906000907f7fa9aafeb8bb803d77de5d84bc2f2edbd842ca91b20cd5020aa21dfe26ab0be9908290a492915050565b600a546001600160a01b03163314610b51576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610b699082611bae565b505050565b600a546001600160a01b03163314610b99576040516302b6341b60e41b815260040160405180910390fd5b6000828152600c60205260409020610b699082611c1b565b600a546000906001600160a01b03163314610bdf576040516302b6341b60e41b815260040160405180910390fd5b60008383604051602001610bf4929190612378565b60405160208183030381529060405280519060200120905084600014610c2e576000858152601660205260409020610c2c9082611c1b565b505b6040805180820182526001600160a01b0380871682526020808301878152600086815260109092529390209151825491166001600160a01b0319909116178155905160019091015590509392505050565b600a546001600160a01b03163314610caa576040516302b6341b60e41b815260040160405180910390fd5b6000818152601c602052604081205490819003610cda576040516366012df560e11b815260040160405180910390fd5b6000818152601d602090815260408083208054600019908101909155601e80549091019055848352600b8252808320839055601c90915280822082905551839183917f410c5c259085cde81fedf70c1aa308ec839373c26e9b7ada6560a2aca0254eb69190a35050565b600a546001600160a01b03163314610d6f576040516302b6341b60e41b815260040160405180910390fd5b600081604051602001610d82919061240c565b60408051601f198184030181529181528151602092830120600086815260199093529120909150610db39082611bae565b50505050565b6000818152601c602052604081205482908203610de9576040516366012df560e11b815260040160405180910390fd5b6000838152600c60205260409020610e0090611c27565b9392505050565b6000818152601c602052604081205482908203610e37576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260409020610e0090611c27565b600a546001600160a01b03163314610e79576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610b699082611c31565b6000818152601c602052604081205460609183919003610ec4576040516366012df560e11b815260040160405180910390fd5b6000838152600d60205260409020610e0090611c46565b600a546000906001600160a01b03163314610f09576040516302b6341b60e41b815260040160405180910390fd5b604051634e6f746560e01b6020820152602481018490526044810183905260009060640160405160208183030381529060405280519060200120905084600014610f67576000858152601760205260409020610f659082611c1b565b505b6040805180820182529485526020808601948552600083815260119091522093518455915160019093019290925592915050565b6000818152601c602052604081205460609183919003610fce576040516366012df560e11b815260040160405180910390fd5b6000838152601760205260408120610fe590611c46565b9050805167ffffffffffffffff81111561100157611001612092565b60405190808252806020026020018201604052801561104657816020015b604080518082019091526000808252602082015281526020019060019003908161101f5790505b50925060005b81518110156110d65760008282815181106110695761106961243a565b6020026020010151905060116000828152602001908152602001600020604051806040016040529081600082015481526020016001820154815250508583815181106110b7576110b761243a565b60200260200101819052505080806110ce906123f3565b91505061104c565b505050919050565b60008181526013602052604090208054606091906110fb906123a9565b80601f0160208091040260200160405190810160405280929190818152602001828054611127906123a9565b80156111745780601f1061114957610100808354040283529160200191611174565b820191906000526020600020905b81548152906001019060200180831161115757829003601f168201915b50505050509050919050565b6000818152601c6020526040812054829082036111b0576040516366012df560e11b815260040160405180910390fd5b610e0083611c53565b600a546000906001600160a01b031633146111e7576040516302b6341b60e41b815260040160405180910390fd5b6000826040516020016111fa919061240c565b604051602081830303815290604052805190602001209050836000146112345760008481526019602052604090206112329082611c1b565b505b600081815260136020526040902061124c848261249e565b509392505050565b6000818152601c602052604081205482908203611284576040516366012df560e11b815260040160405180910390fd5b6000838152601660205260409020610e0090611c27565b600a546040516370a0823160e01b81526001600160a01b03838116600483015260009283929116906370a0823190602401602060405180830381865afa1580156112e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130d919061255e565b905060005b818110156113c257600a54604051632f745c5960e01b81526001600160a01b038681166004830152602482018490526000921690632f745c5990604401602060405180830381865afa15801561136c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611390919061255e565b6000818152601d60205260409020549091506113ac9085612577565b93505080806113ba906123f3565b915050611312565b5050919050565b600a546001600160a01b031633146113f4576040516302b6341b60e41b815260040160405180910390fd5b6000828152601c6020526040812054839103611423576040516366012df560e11b815260040160405180910390fd5b6000838152600b602052604080822084905551839185917ff0aea9f7b630d17e54614f5667704230d832f3c25c0ebbbd2cd7b52914ce11aa9190a3505050565b6000818152601c602052604081205460609183919003611496576040516366012df560e11b815260040160405180910390fd5b6000838152601960205260409020610e0090611c46565b6000818152601c6020526040812054829082036114dd576040516366012df560e11b815260040160405180910390fd5b50506000908152601c602052604090205490565b6000828152601c6020526040812054839103611520576040516366012df560e11b815260040160405180910390fd5b600a546001600160a01b03163314801590611555575061153f83611c53565b6001600160a01b0316336001600160a01b031614155b1561157357604051631a64ce6560e11b815260040160405180910390fd5b600083815260156020526040902061158b838261249e565b50827f6d10c59cedadc720a2e20f54f0a461ef82bd35f762430e32ef049dd6d7fc2730836040516115bc9190611f90565b60405180910390a2505050565b6000818152601c6020526040812054829082036115f9576040516366012df560e11b815260040160405180910390fd5b6000838152600e60205260409020610e0090611c27565b6000818152601c602052604081205460609183919003611643576040516366012df560e11b815260040160405180910390fd5b600083815260166020526040812061165a90611c46565b9050805167ffffffffffffffff81111561167657611676612092565b6040519080825280602002602001820160405280156116bb57816020015b60408051808201909152600080825260208201528152602001906001900390816116945790505b50925060005b81518110156110d65760008282815181106116de576116de61243a565b602090810291909101810151600081815260108352604090819020815180830190925280546001600160a01b03168252600101549281019290925286519092508690849081106117305761173061243a565b6020026020010181905250508080611747906123f3565b9150506116c1565b606060018054610893906123a9565b6000818152601c60205260408120548290820361178e576040516366012df560e11b815260040160405180910390fd5b6000838152600d60205260409020610e0090611c27565b6000818152601c6020526040812054606091839190036117d8576040516366012df560e11b815260040160405180910390fd5b600083815260156020526040902080546117f1906123a9565b80601f016020809104026020016040519081016040528092919081815260200182805461181d906123a9565b801561186a5780601f1061183f5761010080835404028352916020019161186a565b820191906000526020600020905b81548152906001019060200180831161184d57829003601f168201915b5050505050915050919050565b6000818152601c6020526040812054606091839190036118aa576040516366012df560e11b815260040160405180910390fd5b6000838152600c60205260409020610e0090611c46565b600a546001600160a01b031633146118ec576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610b699082611c1b565b600a546001600160a01b0316331461192f576040516302b6341b60e41b815260040160405180910390fd5b6000828152600e60205260409020610b699082611bae565b6000818152601c60205260408120546060918391900361197a576040516366012df560e11b815260040160405180910390fd5b600083815260196020526040812061199190611c46565b9050805167ffffffffffffffff8111156119ad576119ad612092565b6040519080825280602002602001820160405280156119e057816020015b60608152602001906001900390816119cb5790505b50925060005b81518110156110d6576000828281518110611a0357611a0361243a565b60200260200101519050601360008281526020019081526020016000208054611a2b906123a9565b80601f0160208091040260200160405190810160405280929190818152602001828054611a57906123a9565b8015611aa45780601f10611a7957610100808354040283529160200191611aa4565b820191906000526020600020905b815481529060010190602001808311611a8757829003601f168201915b5050505050858381518110611abb57611abb61243a565b6020026020010181905250508080611ad2906123f3565b9150506119e6565b600a546001600160a01b03163314611b05576040516302b6341b60e41b815260040160405180910390fd5b6000828152600d60205260409020610b699082611ccf565b6000818152601c602052604081205460609183919003611b50576040516366012df560e11b815260040160405180910390fd5b6000838152600e60205260409020610e0090611c46565b6000818152601c602052604081205482908203611b97576040516366012df560e11b815260040160405180910390fd5b6000838152601760205260409020610e0090611c27565b6000610e008383611ce4565b6000611bc784868361258a565b506001611bd582848361258a565b507f414cd0b34676984f09a5f76ce9718d4062e50283abe0e7e274a9a5b4e0c99c308484848442604051611c0d959493929190612673565b60405180910390a150505050565b6000610e008383611dd7565b6000610786825490565b6000610e00836001600160a01b038416611ce4565b60606000610e0083611e26565b6000818152601c602052604080822054600a5491516331a9108f60e11b81526004810182905290916001600160a01b031690636352211e90602401602060405180830381865afa158015611cab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0091906126ad565b6000610e00836001600160a01b038416611dd7565b60008181526001830160205260408120548015611dcd576000611d086001836126ca565b8554909150600090611d1c906001906126ca565b9050818114611d81576000866000018281548110611d3c57611d3c61243a565b9060005260206000200154905080876000018481548110611d5f57611d5f61243a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611d9257611d926126dd565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610786565b6000915050610786565b6000818152600183016020526040812054611e1e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610786565b506000610786565b60608160000180548060200260200160405190810160405280929190818152602001828054801561117457602002820191906000526020600020905b815481526020019060010190808311611e625750505050509050919050565b600060208284031215611e9357600080fd5b5035919050565b600060208284031215611eac57600080fd5b81356001600160e01b031981168114610e0057600080fd5b6001600160a01b0381168114611ed957600080fd5b50565b600080600060608486031215611ef157600080fd5b833592506020840135611f0381611ec4565b929592945050506040919091013590565b600080600060608486031215611f2957600080fd5b505081359360208301359350604090920135919050565b60005b83811015611f5b578181015183820152602001611f43565b50506000910152565b60008151808452611f7c816020860160208601611f40565b601f01601f19169290920160200192915050565b602081526000610e006020830184611f64565b60008083601f840112611fb557600080fd5b50813567ffffffffffffffff811115611fcd57600080fd5b602083019150836020828501011115611fe557600080fd5b9250929050565b60008060008060006060868803121561200457600080fd5b853567ffffffffffffffff8082111561201c57600080fd5b61202889838a01611fa3565b9097509550602088013591508082111561204157600080fd5b5061204e88828901611fa3565b909450925050604086013561206281611ec4565b809150509295509295909350565b6000806040838503121561208357600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156120bb57600080fd5b82359150602083013567ffffffffffffffff808211156120da57600080fd5b818501915085601f8301126120ee57600080fd5b81358181111561210057612100612092565b604051601f8201601f19908116603f0116810190838211818310171561212857612128612092565b8160405282815288602084870101111561214157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b815181526020808301519082015260408101610786565b81516001600160a01b031681526020808301519082015260408101610786565b600080604083850312156121ad57600080fd5b8235915060208301356121bf81611ec4565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561220b5783516001600160a01b0316835292840192918401916001016121e6565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156122615761225184835180518252602090810151910152565b9284019290850190600101612234565b5091979650505050505050565b60006020828403121561228057600080fd5b8135610e0081611ec4565b6020808252825182820181905260009190848201906040850190845b8181101561220b578351835292840192918401916001016122a7565b602080825282518282018190526000919060409081850190868401855b828110156122615761230684835180516001600160a01b03168252602090810151910152565b92840192908501906001016122e0565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561236b57603f19888603018452612359858351611f64565b9450928501929085019060010161233d565b5092979650505050505050565b6545524337323160d01b815260609290921b6bffffffffffffffffffffffff19166006830152601a820152603a0190565b600181811c908216806123bd57607f821691505b60208210810361073457634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612405576124056123dd565b5060010190565b65416e7955726960d01b81526000825161242d816006850160208701611f40565b9190910160060192915050565b634e487b7160e01b600052603260045260246000fd5b601f821115610b6957600081815260208120601f850160051c810160208610156124775750805b601f850160051c820191505b8181101561249657828155600101612483565b505050505050565b815167ffffffffffffffff8111156124b8576124b8612092565b6124cc816124c684546123a9565b84612450565b602080601f83116001811461250157600084156124e95750858301515b600019600386901b1c1916600185901b178555612496565b600085815260208120601f198616915b8281101561253057888601518255948401946001909101908401612511565b508582101561254e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561257057600080fd5b5051919050565b80820180821115610786576107866123dd565b67ffffffffffffffff8311156125a2576125a2612092565b6125b6836125b083546123a9565b83612450565b6000601f8411600181146125ea57600085156125d25750838201355b600019600387901b1c1916600186901b1783556107fd565b600083815260209020601f19861690835b8281101561261b57868501358255602094850194600190920191016125fb565b50868210156126385760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60608152600061268760608301878961264a565b828103602084015261269a81868861264a565b9150508260408301529695505050505050565b6000602082840312156126bf57600080fd5b8151610e0081611ec4565b81810381811115610786576107866123dd565b634e487b7160e01b600052603160045260246000fdfea264697066735822122061781f9ecc9ea6d4accc2f0c3bb1e8f3606ef155ed6129199faa66c6f075eddc64736f6c63430008120033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/contracts/Linklist.sol b/contracts/Linklist.sol index acb4de306..63bc74653 100644 --- a/contracts/Linklist.sol +++ b/contracts/Linklist.sol @@ -1,10 +1,8 @@ // SPDX-License-Identifier: MIT -// slither-disable-start unused-return pragma solidity 0.8.18; import {ILinklist} from "./interfaces/ILinklist.sol"; import {LinklistBase} from "./base/LinklistBase.sol"; -import {ERC721} from "./base/ERC721.sol"; import {Events} from "./libraries/Events.sol"; import {DataTypes} from "./libraries/DataTypes.sol"; import { @@ -100,7 +98,7 @@ contract Linklist is string memory uri ) external override onlyExistingToken(tokenId) { // caller must be web3Entry or owner - if (msg.sender != Web3Entry && msg.sender != ownerOf(tokenId)) + if (msg.sender != Web3Entry && msg.sender != _ownerOf(tokenId)) revert ErrCallerNotWeb3EntryOrNotOwner(); _uris[tokenId] = uri; @@ -426,16 +424,15 @@ contract Linklist is return _linkTypes[tokenId]; } - // slither-disable-start naming-convention - // solhint-disable-next-line func-name-mixedcase + /// @inheritdoc ILinklist + // solhint-disable func-name-mixedcase + // slither-disable-next-line naming-convention function Uri( uint256 tokenId ) external view override onlyExistingToken(tokenId) returns (string memory) { return _uris[tokenId]; } - // slither-disable-end naming-convention - /// @inheritdoc ILinklist function characterOwnerOf( uint256 tokenId @@ -444,50 +441,33 @@ contract Linklist is } /// @inheritdoc ILinklist - function balanceOf(uint256 characterId) public view override returns (uint256) { + function totalSupply() external view override returns (uint256) { + return _totalSupply; + } + + /// @inheritdoc ILinklist + function balanceOf(uint256 characterId) external view override returns (uint256) { return _linklistBalances[characterId]; } - // slither-disable-next-line calls-loop - function balanceOf(address account) public view override(ERC721) returns (uint256 balance) { + /// @inheritdoc ILinklist + function balanceOf(address account) external view override returns (uint256 balance) { uint256 characterCount = IERC721(Web3Entry).balanceOf(account); for (uint256 i = 0; i < characterCount; i++) { uint256 characterId = IERC721Enumerable(Web3Entry).tokenOfOwnerByIndex(account, i); - balance += balanceOf(characterId); + balance += _linklistBalances[characterId]; } } - /// @inheritdoc ERC721 + /// @inheritdoc ILinklist function ownerOf( uint256 tokenId - ) public view override(ERC721) onlyExistingToken(tokenId) returns (address) { - uint256 characterId = _linklistOwners[tokenId]; - address owner = IERC721(Web3Entry).ownerOf(characterId); - return owner; + ) external view override onlyExistingToken(tokenId) returns (address) { + return _ownerOf(tokenId); } - /// @inheritdoc ILinklist - function totalSupply() external view override returns (uint256) { - return _totalSupply; - } - - function _safeTransfer( - address, - address, - uint256, - bytes memory // solhint-disable-next-line no-empty-blocks - ) internal pure override { - // this function will do nothing, as linklist is a character bounded token - // users should never transfer a linklist directly - } - - function _transfer( - address, - address, - uint256 // solhint-disable-next-line no-empty-blocks - ) internal pure override { - // this function will do nothing, as linklist is a character bounded token - // users should never transfer a linklist directly + function _ownerOf(uint256 tokenId) internal view returns (address) { + uint256 characterId = _linklistOwners[tokenId]; + return IERC721(Web3Entry).ownerOf(characterId); } } -// slither-disable-end unused-return diff --git a/contracts/Web3Entry.sol b/contracts/Web3Entry.sol index 6bafa27e4..048a56e5f 100644 --- a/contracts/Web3Entry.sol +++ b/contracts/Web3Entry.sol @@ -1,9 +1,869 @@ // SPDX-License-Identifier: MIT + pragma solidity 0.8.18; -import {Web3EntryBase} from "./Web3EntryBase.sol"; +import {IWeb3Entry} from "./interfaces/IWeb3Entry.sol"; +import {ILinklist} from "./interfaces/ILinklist.sol"; +import {NFTBase} from "./base/NFTBase.sol"; +import {Web3EntryStorage} from "./storage/Web3EntryStorage.sol"; +import {Web3EntryExtendStorage} from "./storage/Web3EntryExtendStorage.sol"; +import {DataTypes} from "./libraries/DataTypes.sol"; +import {Constants} from "./libraries/Constants.sol"; +import {Events} from "./libraries/Events.sol"; +import {CharacterLib} from "./libraries/CharacterLib.sol"; +import {PostLib} from "./libraries/PostLib.sol"; +import {OperatorLib} from "./libraries/OperatorLib.sol"; +import {LinkLib} from "./libraries/LinkLib.sol"; +import {LinklistLib} from "./libraries/LinklistLib.sol"; +import {MetaTxLib} from "./libraries/MetaTxLib.sol"; +import {ValidationLib} from "./libraries/ValidationLib.sol"; +import {OP} from "./libraries/OP.sol"; +import { + ErrSocialTokenExists, + ErrNotCharacterOwner, + ErrNotEnoughPermission, + ErrNotEnoughPermissionForThisNote, + ErrCharacterNotExists +} from "./libraries/Error.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; + +contract Web3Entry is + IWeb3Entry, + Multicall, + NFTBase, + Web3EntryStorage, + Initializable, + Web3EntryExtendStorage +{ + using EnumerableSet for EnumerableSet.Bytes32Set; + using EnumerableSet for EnumerableSet.AddressSet; + + // solhint-disable-next-line private-vars-leading-underscore + uint256 internal constant REVISION = 4; + + modifier validateCallerPermission(uint256 characterId, uint256 permissionId) { + _validateCallerPermission(characterId, permissionId); + _; + } + + modifier onlyExistingToken(uint256 tokenId) { + if (!_exists(tokenId)) revert ErrCharacterNotExists(tokenId); + _; + } + + /// @inheritdoc IWeb3Entry + function initialize( + string calldata name_, + string calldata symbol_, + address linklist_, + address mintNFTImpl_, + address periphery_, + address newbieVilla_ + ) external override reinitializer(3) { + super._initialize(name_, symbol_); + _linklist = linklist_; + MINT_NFT_IMPL = mintNFTImpl_; + _periphery = periphery_; + _newbieVilla = newbieVilla_; + + emit Events.Web3EntryInitialized(block.timestamp); + } + + /// @inheritdoc IWeb3Entry + function grantOperatorPermissions( + uint256 characterId, + address operator, + uint256 permissionBitMap + ) external override validateCallerPermission(characterId, OP.GRANT_OPERATOR_PERMISSIONS) { + OperatorLib.grantOperatorPermissions(characterId, operator, permissionBitMap); + } + + /// @inheritdoc IWeb3Entry + function grantOperatorPermissionsWithSig( + uint256 characterId, + address operator, + uint256 permissionBitMap, + DataTypes.EIP712Signature calldata signature + ) external override { + if (!_callerIsCharacterOwner(signature.signer, characterId)) revert ErrNotCharacterOwner(); + + MetaTxLib.validateGrantOperatorPermissionsSignature( + signature, + characterId, + operator, + permissionBitMap + ); + OperatorLib.grantOperatorPermissions(characterId, operator, permissionBitMap); + } + + /// @inheritdoc IWeb3Entry + function grantOperators4Note( + uint256 characterId, + uint256 noteId, + address[] calldata blocklist, + address[] calldata allowlist + ) external override validateCallerPermission(characterId, OP.GRANT_OPERATORS_FOR_NOTE) { + ValidationLib.validateNoteExists(characterId, noteId); + OperatorLib.grantOperators4Note(characterId, noteId, blocklist, allowlist); + } + + /// @inheritdoc IWeb3Entry + function createCharacter( + DataTypes.CreateCharacterData calldata vars + ) external override returns (uint256 characterId) { + return _createCharacter(vars, true); + } + + /// @inheritdoc IWeb3Entry + function setHandle( + uint256 characterId, + string calldata newHandle + ) external override validateCallerPermission(characterId, OP.SET_HANDLE) { + CharacterLib.setHandle(characterId, newHandle); + } + + /// @inheritdoc IWeb3Entry + function setSocialToken( + uint256 characterId, + address tokenAddress + ) external override validateCallerPermission(characterId, OP.SET_SOCIAL_TOKEN) { + // check if the social token exists + if (_characterById[characterId].socialToken != address(0)) revert ErrSocialTokenExists(); + + CharacterLib.setSocialToken(characterId, tokenAddress); + } + + /// @inheritdoc IWeb3Entry + function setPrimaryCharacterId(uint256 characterId) external override { + if (!_callerIsCharacterOwner(msg.sender, characterId)) revert ErrNotCharacterOwner(); + + // `tx.origin` is used here because the caller may be the periphery contract + address owner = tx.origin; // solhint-disable-line avoid-tx-origin + uint256 oldCharacterId = _primaryCharacterByAddress[owner]; + _primaryCharacterByAddress[owner] = characterId; + + emit Events.SetPrimaryCharacterId(msg.sender, characterId, oldCharacterId); + } + + /// @inheritdoc IWeb3Entry + function setCharacterUri( + uint256 characterId, + string calldata newUri + ) external override validateCallerPermission(characterId, OP.SET_CHARACTER_URI) { + _characterById[characterId].uri = newUri; + + emit Events.SetCharacterUri(characterId, newUri); + } + + /// @inheritdoc IWeb3Entry + function setLinklistUri(uint256 linklistId, string calldata uri) external override { + uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); + _validateCallerPermission(characterId, OP.SET_LINKLIST_URI); + + LinklistLib.setLinklistUri(linklistId, uri, _linklist); + } + + /// @inheritdoc IWeb3Entry + function setLinklistType(uint256 linklistId, bytes32 linkType) external override { + uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); + _validateCallerPermission(characterId, OP.SET_LINKLIST_TYPE); + + LinklistLib.setLinklistType(characterId, linklistId, linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function linkCharacter( + DataTypes.linkCharacterData calldata vars + ) + external + override + onlyExistingToken(vars.toCharacterId) + validateCallerPermission(vars.fromCharacterId, OP.LINK_CHARACTER) + { + LinkLib.linkCharacter( + vars.fromCharacterId, + vars.toCharacterId, + vars.linkType, + vars.data, + _linklist + ); + } + + /// @inheritdoc IWeb3Entry + function unlinkCharacter( + DataTypes.unlinkCharacterData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_CHARACTER) { + LinkLib.unlinkCharacter(vars.fromCharacterId, vars.toCharacterId, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function createThenLinkCharacter( + DataTypes.createThenLinkCharacterData calldata vars + ) + external + override + validateCallerPermission(vars.fromCharacterId, OP.CREATE_THEN_LINK_CHARACTER) + returns (uint256 characterId) + { + // create character + characterId = _createCharacter( + DataTypes.CreateCharacterData({ + to: vars.to, + handle: _addressToHexString(vars.to), + uri: "", + linkModule: address(0), + linkModuleInitData: "" + }), + false + ); + + // link character + LinkLib.linkCharacter(vars.fromCharacterId, characterId, vars.linkType, "", _linklist); + } + + /// @inheritdoc IWeb3Entry + function linkNote( + DataTypes.linkNoteData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.LINK_NOTE) { + ValidationLib.validateNoteExists(vars.toCharacterId, vars.toNoteId); + + LinkLib.linkNote( + vars.fromCharacterId, + vars.toCharacterId, + vars.toNoteId, + vars.linkType, + vars.data, + _linklist + ); + } + + /// @inheritdoc IWeb3Entry + function unlinkNote( + DataTypes.unlinkNoteData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_NOTE) { + LinkLib.unlinkNote( + vars.fromCharacterId, + vars.toCharacterId, + vars.toNoteId, + vars.linkType, + _linklist + ); + } + + /// @inheritdoc IWeb3Entry + function linkERC721( + DataTypes.linkERC721Data calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.LINK_ERC721) { + LinkLib.linkERC721( + vars.fromCharacterId, + vars.tokenAddress, + vars.tokenId, + vars.linkType, + _linklist + ); + } + + /// @inheritdoc IWeb3Entry + function unlinkERC721( + DataTypes.unlinkERC721Data calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ERC721) { + LinkLib.unlinkERC721( + vars.fromCharacterId, + vars.tokenAddress, + vars.tokenId, + vars.linkType, + _linklist + ); + } + + /// @inheritdoc IWeb3Entry + function linkAddress( + DataTypes.linkAddressData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.LINK_ADDRESS) { + LinkLib.linkAddress(vars.fromCharacterId, vars.ethAddress, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function unlinkAddress( + DataTypes.unlinkAddressData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ADDRESS) { + LinkLib.unlinkAddress(vars.fromCharacterId, vars.ethAddress, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function linkAnyUri( + DataTypes.linkAnyUriData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.LINK_ANYURI) { + LinkLib.linkAnyUri(vars.fromCharacterId, vars.toUri, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function unlinkAnyUri( + DataTypes.unlinkAnyUriData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ANYURI) { + LinkLib.unlinkAnyUri(vars.fromCharacterId, vars.toUri, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function linkLinklist( + DataTypes.linkLinklistData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.LINK_LINKLIST) { + LinkLib.linkLinklist(vars.fromCharacterId, vars.toLinkListId, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function unlinkLinklist( + DataTypes.unlinkLinklistData calldata vars + ) external override validateCallerPermission(vars.fromCharacterId, OP.UNLINK_LINKLIST) { + LinkLib.unlinkLinklist(vars.fromCharacterId, vars.toLinkListId, vars.linkType, _linklist); + } + + /// @inheritdoc IWeb3Entry + function setLinkModule4Character( + DataTypes.setLinkModule4CharacterData calldata vars + ) + external + override + validateCallerPermission(vars.characterId, OP.SET_LINK_MODULE_FOR_CHARACTER) + { + CharacterLib.setCharacterLinkModule( + vars.characterId, + vars.linkModule, + vars.linkModuleInitData + ); + } + + /// @inheritdoc IWeb3Entry + function setLinkModule4Note( + DataTypes.setLinkModule4NoteData calldata vars + ) external override validateCallerPermission(vars.characterId, OP.SET_LINK_MODULE_FOR_NOTE) { + // @dev only check operators permission currently + PostLib.setLinkModule4Note( + vars.characterId, + vars.noteId, + vars.linkModule, + vars.linkModuleInitData + ); + } + + /// @inheritdoc IWeb3Entry + function mintNote( + DataTypes.MintNoteData calldata vars + ) external override returns (uint256 tokenId) { + ValidationLib.validateNoteExists(vars.characterId, vars.noteId); + + tokenId = PostLib.mintNote( + vars.characterId, + vars.noteId, + vars.to, + vars.mintModuleData, + MINT_NFT_IMPL + ); + } + + /// @inheritdoc IWeb3Entry + function setMintModule4Note( + DataTypes.setMintModule4NoteData calldata vars + ) external override validateCallerPermission(vars.characterId, OP.SET_MINT_MODULE_FOR_NOTE) { + ValidationLib.validateNoteExists(vars.characterId, vars.noteId); + ValidationLib.validateNoteNotLocked(vars.characterId, vars.noteId); + + PostLib.setMintModule4Note( + vars.characterId, + vars.noteId, + vars.mintModule, + vars.mintModuleInitData + ); + } + + /// @inheritdoc IWeb3Entry + function postNote( + DataTypes.PostNoteData calldata vars + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + PostLib.postNoteWithLink(vars, noteId, 0, 0, ""); + } + + /// @inheritdoc IWeb3Entry + function setNoteUri( + uint256 characterId, + uint256 noteId, + string calldata newUri + ) external override { + _validateCallerPermission4Note(characterId, noteId); + ValidationLib.validateNoteExists(characterId, noteId); + ValidationLib.validateNoteNotLocked(characterId, noteId); + + PostLib.setNoteUri(characterId, noteId, newUri); + } + + /// @inheritdoc IWeb3Entry + function lockNote( + uint256 characterId, + uint256 noteId + ) external override validateCallerPermission(characterId, OP.LOCK_NOTE) { + PostLib.lockNote(characterId, noteId); + } + + /// @inheritdoc IWeb3Entry + function deleteNote( + uint256 characterId, + uint256 noteId + ) external override validateCallerPermission(characterId, OP.DELETE_NOTE) { + PostLib.deleteNote(characterId, noteId); + } + + /// @inheritdoc IWeb3Entry + function postNote4Character( + DataTypes.PostNoteData calldata vars, + uint256 toCharacterId + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_CHARACTER) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_CHARACTER; + bytes32 linkKey = bytes32(toCharacterId); + + PostLib.postNoteWithLink( + vars, + noteId, + linkItemType, + linkKey, + abi.encodePacked(toCharacterId) + ); + } + + /// @inheritdoc IWeb3Entry + function postNote4Address( + DataTypes.PostNoteData calldata vars, + address ethAddress + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ADDRESS) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ADDRESS; + bytes32 linkKey = bytes32(uint256(uint160(ethAddress))); + + PostLib.postNoteWithLink(vars, noteId, linkItemType, linkKey, abi.encodePacked(ethAddress)); + } + + /// @inheritdoc IWeb3Entry + function postNote4Linklist( + DataTypes.PostNoteData calldata vars, + uint256 toLinklistId + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_LINKLIST) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_LINKLIST; + bytes32 linkKey = bytes32(toLinklistId); + + PostLib.postNoteWithLink( + vars, + noteId, + linkItemType, + linkKey, + abi.encodePacked(toLinklistId) + ); + } + + /// @inheritdoc IWeb3Entry + function postNote4Note( + DataTypes.PostNoteData calldata vars, + DataTypes.NoteStruct calldata note + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_NOTE) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_NOTE; + bytes32 linkKey = ILinklist(_linklist).addLinkingNote(0, note.characterId, note.noteId); + + PostLib.postNoteWithLink( + vars, + noteId, + linkItemType, + linkKey, + abi.encodePacked(note.characterId, note.noteId) + ); + } + + /// @inheritdoc IWeb3Entry + function postNote4ERC721( + DataTypes.PostNoteData calldata vars, + DataTypes.ERC721Struct calldata erc721 + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ERC721) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ERC721; + bytes32 linkKey = ILinklist(_linklist).addLinkingERC721( + 0, + erc721.tokenAddress, + erc721.erc721TokenId + ); + + PostLib.postNoteWithLink( + vars, + noteId, + linkItemType, + linkKey, + abi.encodePacked(erc721.tokenAddress, erc721.erc721TokenId) + ); + } + + /// @inheritdoc IWeb3Entry + function postNote4AnyUri( + DataTypes.PostNoteData calldata vars, + string calldata uri + ) + external + override + validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ANYURI) + returns (uint256 noteId) + { + noteId = _nextNoteId(vars.characterId); + bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ANYURI; + bytes32 linkKey = ILinklist(_linklist).addLinkingAnyUri(0, uri); + + PostLib.postNoteWithLink(vars, noteId, linkItemType, linkKey, abi.encodePacked(uri)); + } + + /// @inheritdoc IWeb3Entry + function burnLinklist(uint256 linklistId) external override { + // only the owner of the character can burn the linklist through web3Entry contract + uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); + if (!_callerIsCharacterOwner(msg.sender, characterId)) revert ErrNotCharacterOwner(); + + LinklistLib.burnLinklist(characterId, linklistId, _linklist); + } + + /// @inheritdoc IWeb3Entry + function getOperators(uint256 characterId) external view override returns (address[] memory) { + return _operatorsByCharacter[characterId].values(); + } + + /// @inheritdoc IWeb3Entry + function getOperatorPermissions( + uint256 characterId, + address operator + ) external view override returns (uint256) { + return _operatorsPermissionBitMap[characterId][operator]; + } + + /// @inheritdoc IWeb3Entry + function getOperators4Note( + uint256 characterId, + uint256 noteId + ) external view override returns (address[] memory blocklist, address[] memory allowlist) { + DataTypes.Operators4Note storage operators = _operators4Note[characterId][noteId]; + (blocklist, allowlist) = (operators.blocklist.values(), operators.allowlist.values()); + } + + /// @inheritdoc IWeb3Entry + function isOperatorAllowedForNote( + uint256 characterId, + uint256 noteId, + address operator + ) external view override returns (bool) { + return _isOperatorAllowedForNote(characterId, noteId, operator); + } + + /// @inheritdoc IWeb3Entry + function getPrimaryCharacterId(address account) external view override returns (uint256) { + return _primaryCharacterByAddress[account]; + } + + /// @inheritdoc IWeb3Entry + function isPrimaryCharacter(uint256 characterId) external view override returns (bool) { + address account = ownerOf(characterId); + return characterId == _primaryCharacterByAddress[account]; + } + + /// @inheritdoc IWeb3Entry + function getCharacter( + uint256 characterId + ) external view override onlyExistingToken(characterId) returns (DataTypes.Character memory) { + return _characterById[characterId]; + } + + /// @inheritdoc IWeb3Entry + function getCharacterByHandle( + string calldata handle + ) external view override returns (DataTypes.Character memory) { + uint256 characterId = _characterIdByHandleHash[_handleHash(handle)]; + return _characterById[characterId]; + } + + /// @inheritdoc IWeb3Entry + function getHandle( + uint256 characterId + ) external view override onlyExistingToken(characterId) returns (string memory) { + return _characterById[characterId].handle; + } + + /// @inheritdoc IWeb3Entry + function getCharacterUri(uint256 characterId) external view override returns (string memory) { + return tokenURI(characterId); + } + + /// @inheritdoc IWeb3Entry + function getNote( + uint256 characterId, + uint256 noteId + ) external view override returns (DataTypes.Note memory) { + return _noteByIdByCharacter[characterId][noteId]; + } + + /// @inheritdoc IWeb3Entry + function getLinklistUri(uint256 tokenId) external view override returns (string memory) { + return ILinklist(_linklist).Uri(tokenId); + } + + /// @inheritdoc IWeb3Entry + function getLinklistId( + uint256 characterId, + bytes32 linkType + ) external view override returns (uint256) { + return _attachedLinklists[characterId][linkType]; + } + + /// @inheritdoc IWeb3Entry + function getLinklistType(uint256 linkListId) external view override returns (bytes32) { + return ILinklist(_linklist).getLinkType(linkListId); + } + + /// @inheritdoc IWeb3Entry + function getLinklistContract() external view override returns (address) { + return _linklist; + } + + /// @inheritdoc IWeb3Entry + function getDomainSeparator() external view override returns (bytes32) { + return MetaTxLib._calculateDomainSeparator(); + } + + /// @inheritdoc IWeb3Entry + function nonces(address owner) external view override returns (uint256) { + return _sigNonces[owner]; + } + + /// @inheritdoc IWeb3Entry + function getRevision() external pure override returns (uint256) { + return REVISION; + } + + /** + * @notice Burns a web3Entry character nft. + * @param tokenId The token ID to burn. + */ + function burn(uint256 tokenId) public virtual override { + // clear handle + bytes32 handleHash = _handleHash(_characterById[tokenId].handle); + _characterIdByHandleHash[handleHash] = 0; + + // clear character + delete _characterById[tokenId]; + + // burn token + super.burn(tokenId); + } + + /** + * @notice Returns the associated URI with a given character. + * @param characterId The character ID to query. + * @return The token URI. + */ + function tokenURI( + uint256 characterId + ) public view override onlyExistingToken(characterId) returns (string memory) { + return _characterById[characterId].uri; + } + + function _createCharacter( + DataTypes.CreateCharacterData memory vars, + bool validateHandle + ) internal returns (uint256 characterId) { + characterId = ++_characterCounter; + // mint character nft + _safeMint(vars.to, characterId); + + CharacterLib.createCharacter( + vars.to, + vars.handle, + vars.uri, + vars.linkModule, + vars.linkModuleInitData, + characterId, + validateHandle + ); + } + + /** + * @dev Operators will be reset to blank before the characters are transferred in order to grant the + * whole control power to receivers of character transfers. + * If character is transferred from newbieVilla contract, don't clear operators. + * + * Permissions4Note is left unset, because permissions for notes are always stricter than default. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override { + // clear operators if character is transferred from non-newbieVilla contract + if (from != _newbieVilla) { + // clear operators + OperatorLib.clearOperators(tokenId); + + // reset if `tokenId` is primary character of `from` account + if (_primaryCharacterByAddress[from] == tokenId) { + _primaryCharacterByAddress[from] = 0; + } + } + + super._beforeTokenTransfer(from, to, tokenId); + } + + function _afterTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override { + // set primary character if `to` account has no primary character + if (_primaryCharacterByAddress[to] == 0) { + _primaryCharacterByAddress[to] = tokenId; + } + + super._afterTokenTransfer(from, to, tokenId); + } + + function _nextNoteId(uint256 characterId) internal returns (uint256) { + return ++_characterById[characterId].noteCount; + } + + /** + * @dev It will first check note permission, and then check operators permission. + */ + function _isOperatorAllowedForNote( + uint256 characterId, + uint256 noteId, + address operator + ) internal view returns (bool) { + DataTypes.Operators4Note storage op = _operators4Note[characterId][noteId]; + + // check blocklist + if (op.blocklist.contains(operator)) { + return false; + } + // check allowlist + if (op.allowlist.contains(operator)) { + return true; + } + // check character operator permission + return _checkBit(_operatorsPermissionBitMap[characterId][operator], OP.SET_NOTE_URI); + } + + function _validateCallerPermission(uint256 characterId, uint256 permissionId) internal view { + // check character owner + if (_callerIsCharacterOwner(msg.sender, characterId)) { + return; + } + + // check operator permission for caller + address caller = (msg.sender == _periphery) ? tx.origin : msg.sender; // solhint-disable-line avoid-tx-origin + if (_checkBit(_operatorsPermissionBitMap[characterId][caller], permissionId)) { + return; + } + + revert ErrNotEnoughPermission(); + } + + function _callerIsCharacterOwner( + address caller, + uint256 characterId + ) internal view returns (bool) { + address owner = ownerOf(characterId); + + if (caller == owner) { + // caller is character owner + return true; + } + + // solhint-disable-next-line avoid-tx-origin + if (caller == _periphery && tx.origin == owner) { + // caller is periphery, and tx.origin is character owner + return true; + } + + return false; + } + + function _validateCallerPermission4Note(uint256 characterId, uint256 noteId) internal view { + // check character owner + if (_callerIsCharacterOwner(msg.sender, characterId)) { + return; + } + + // check note permission for caller + address caller = (msg.sender == _periphery) ? tx.origin : msg.sender; // solhint-disable-line avoid-tx-origin + if (_isOperatorAllowedForNote(characterId, noteId, caller)) { + return; + } + + revert ErrNotEnoughPermissionForThisNote(); + } + + /** + * @dev _checkBit checks if the value of the i'th bit of x is 1 + */ + function _checkBit(uint256 x, uint256 i) internal pure returns (bool) { + return (x >> i) & 1 == 1; + } + + /** + * @dev _addressToHexString converts an address to its ASCII `string hexadecimal representation. + */ + function _addressToHexString(address addr) internal pure returns (string memory) { + bytes16 symbols = "0123456789abcdef"; + uint256 value = uint256(uint160(addr)); + + bytes memory buffer = new bytes(42); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 41; i > 1; ) { + buffer[i] = symbols[value & 0xf]; + value >>= 4; -// solhint-disable-next-line no-empty-blocks -contract Web3Entry is Web3EntryBase { + unchecked { + --i; + } + } + return string(buffer); + } + function _handleHash(string memory handle) internal pure returns (bytes32) { + return keccak256(bytes(handle)); + } } diff --git a/contracts/Web3EntryBase.sol b/contracts/Web3EntryBase.sol deleted file mode 100644 index 3c2f11216..000000000 --- a/contracts/Web3EntryBase.sol +++ /dev/null @@ -1,1089 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.18; - -import {IWeb3Entry} from "./interfaces/IWeb3Entry.sol"; -import {ILinklist} from "./interfaces/ILinklist.sol"; -import {NFTBase} from "./base/NFTBase.sol"; -import {Web3EntryStorage} from "./storage/Web3EntryStorage.sol"; -import {Web3EntryExtendStorage} from "./storage/Web3EntryExtendStorage.sol"; -import {DataTypes} from "./libraries/DataTypes.sol"; -import {Constants} from "./libraries/Constants.sol"; -import {Events} from "./libraries/Events.sol"; -import {CharacterLogic} from "./libraries/CharacterLogic.sol"; -import {PostLogic} from "./libraries/PostLogic.sol"; -import {OperatorLogic} from "./libraries/OperatorLogic.sol"; -import {LinkLogic} from "./libraries/LinkLogic.sol"; -import {LinklistLogic} from "./libraries/LinklistLogic.sol"; -import {OP} from "./libraries/OP.sol"; -import { - ErrSocialTokenExists, - ErrHandleExists, - ErrNotCharacterOwner, - ErrNotEnoughPermission, - ErrNotEnoughPermissionForThisNote, - ErrCharacterNotExists, - ErrNoteIsDeleted, - ErrNoteNotExists, - ErrNoteLocked, - ErrHandleLengthInvalid, - ErrHandleContainsInvalidCharacters, - ErrSignatureExpired, - ErrSignatureInvalid, - ErrTokenNotExists -} from "./libraries/Error.sol"; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; -import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -contract Web3EntryBase is - IWeb3Entry, - Multicall, - NFTBase, - Web3EntryStorage, - Initializable, - Web3EntryExtendStorage -{ - using EnumerableSet for EnumerableSet.Bytes32Set; - using EnumerableSet for EnumerableSet.AddressSet; - - // solhint-disable-next-line private-vars-leading-underscore - uint256 internal constant REVISION = 4; - - modifier onlyExistingToken(uint256 tokenId) { - if (!_exists(tokenId)) revert ErrTokenNotExists(); - _; - } - - /// @inheritdoc IWeb3Entry - function initialize( - string calldata name_, - string calldata symbol_, - address linklist_, - address mintNFTImpl_, - address periphery_, - address newbieVilla_ - ) external override reinitializer(3) { - super._initialize(name_, symbol_); - _linklist = linklist_; - MINT_NFT_IMPL = mintNFTImpl_; - _periphery = periphery_; - _newbieVilla = newbieVilla_; - - emit Events.Web3EntryInitialized(block.timestamp); - } - - /// @inheritdoc IWeb3Entry - function grantOperatorPermissions( - uint256 characterId, - address operator, - uint256 permissionBitMap - ) external override { - _validateCallerPermission(characterId, OP.GRANT_OPERATOR_PERMISSIONS); - _grantOperatorPermissions(characterId, operator, permissionBitMap); - } - - /// @inheritdoc IWeb3Entry - function grantOperatorPermissionsWithSig( - uint256 characterId, - address operator, - uint256 permissionBitMap, - DataTypes.EIP712Signature calldata sig - ) external override { - address owner = ownerOf(characterId); - - unchecked { - bytes32 hashedMessage = keccak256( - abi.encode( - GRANT_OPERATOR_PERMISSIONS_WITH_SIG_TYPEHASH, - characterId, - operator, - permissionBitMap, - _sigNonces[owner]++, - sig.deadline - ) - ); - _validateRecoveredAddress( - ECDSA.toTypedDataHash(_calculateDomainSeparator(), hashedMessage), - owner, - sig - ); - } - - _grantOperatorPermissions(characterId, operator, permissionBitMap); - } - - /// @inheritdoc IWeb3Entry - function grantOperators4Note( - uint256 characterId, - uint256 noteId, - address[] calldata blocklist, - address[] calldata allowlist - ) external override { - _validateCallerPermission(characterId, OP.GRANT_OPERATORS_FOR_NOTE); - _validateNoteExists(characterId, noteId); - OperatorLogic.grantOperators4Note( - characterId, - noteId, - blocklist, - allowlist, - _operators4Note - ); - } - - /// @inheritdoc IWeb3Entry - function createCharacter( - DataTypes.CreateCharacterData calldata vars - ) external override returns (uint256 characterId) { - return _createCharacter(vars, true); - } - - /// @inheritdoc IWeb3Entry - function setHandle(uint256 characterId, string calldata newHandle) external override { - _validateCallerPermission(characterId, OP.SET_HANDLE); - - // check if the handle exists - _checkHandleExists(keccak256(bytes(newHandle))); - - // check if the handle is valid - _validateHandle(newHandle); - - CharacterLogic.setHandle(characterId, newHandle, _characterIdByHandleHash, _characterById); - } - - /// @inheritdoc IWeb3Entry - function setSocialToken(uint256 characterId, address tokenAddress) external override { - _validateCallerPermission(characterId, OP.SET_SOCIAL_TOKEN); - - // check if the social token exists - if (_characterById[characterId].socialToken != address(0)) revert ErrSocialTokenExists(); - - CharacterLogic.setSocialToken(characterId, tokenAddress, _characterById); - } - - /// @inheritdoc IWeb3Entry - function setPrimaryCharacterId(uint256 characterId) external override { - _validateCallerIsCharacterOwner(characterId); - - // `tx.origin` is used here because the caller may be the periphery contract - uint256 oldCharacterId = _primaryCharacterByAddress[tx.origin]; - _primaryCharacterByAddress[tx.origin] = characterId; - - emit Events.SetPrimaryCharacterId(msg.sender, characterId, oldCharacterId); - } - - /// @inheritdoc IWeb3Entry - function setCharacterUri(uint256 characterId, string calldata newUri) external override { - _validateCallerPermission(characterId, OP.SET_CHARACTER_URI); - _characterById[characterId].uri = newUri; - - emit Events.SetCharacterUri(characterId, newUri); - } - - /// @inheritdoc IWeb3Entry - function setLinklistUri(uint256 linklistId, string calldata uri) external override { - uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); - _validateCallerPermission(characterId, OP.SET_LINKLIST_URI); - - LinklistLogic.setLinklistUri(linklistId, uri, _linklist); - } - - /// @inheritdoc IWeb3Entry - function setLinklistType(uint256 linklistId, bytes32 linkType) external override { - uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); - _validateCallerPermission(characterId, OP.SET_LINKLIST_TYPE); - - LinklistLogic.setLinklistType( - characterId, - linklistId, - linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function linkCharacter(DataTypes.linkCharacterData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_CHARACTER); - _validateCharacterExists(vars.toCharacterId); - - LinkLogic.linkCharacter( - vars.fromCharacterId, - vars.toCharacterId, - vars.linkType, - vars.data, - _linklist, - _characterById[vars.toCharacterId].linkModule, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkCharacter(DataTypes.unlinkCharacterData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_CHARACTER); - - LinkLogic.unlinkCharacter( - vars.fromCharacterId, - vars.toCharacterId, - vars.linkType, - _linklist, - _attachedLinklists[vars.fromCharacterId][vars.linkType] - ); - } - - /// @inheritdoc IWeb3Entry - function createThenLinkCharacter( - DataTypes.createThenLinkCharacterData calldata vars - ) external override returns (uint256 characterId) { - _validateCallerPermission(vars.fromCharacterId, OP.CREATE_THEN_LINK_CHARACTER); - - // create character - characterId = _createCharacter( - DataTypes.CreateCharacterData({ - to: vars.to, - handle: _addressToHexString(vars.to), - uri: "", - linkModule: address(0), - linkModuleInitData: "" - }), - false - ); - - // link character - LinkLogic.linkCharacter( - vars.fromCharacterId, - characterId, - vars.linkType, - "", - _linklist, - address(0), - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function linkNote(DataTypes.linkNoteData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_NOTE); - _validateNoteExists(vars.toCharacterId, vars.toNoteId); - - LinkLogic.linkNote( - vars.fromCharacterId, - vars.toCharacterId, - vars.toNoteId, - vars.linkType, - vars.data, - _linklist, - _noteByIdByCharacter[vars.toCharacterId][vars.toNoteId].linkModule, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkNote(DataTypes.unlinkNoteData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.UNLINK_NOTE); - - LinkLogic.unlinkNote( - vars.fromCharacterId, - vars.toCharacterId, - vars.toNoteId, - vars.linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function linkERC721(DataTypes.linkERC721Data calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_ERC721); - - LinkLogic.linkERC721( - vars.fromCharacterId, - vars.tokenAddress, - vars.tokenId, - vars.linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkERC721(DataTypes.unlinkERC721Data calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ERC721); - - LinkLogic.unlinkERC721( - vars.fromCharacterId, - vars.tokenAddress, - vars.tokenId, - vars.linkType, - _linklist, - _attachedLinklists[vars.fromCharacterId][vars.linkType] - ); - } - - /// @inheritdoc IWeb3Entry - function linkAddress(DataTypes.linkAddressData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_ADDRESS); - - LinkLogic.linkAddress( - vars.fromCharacterId, - vars.ethAddress, - vars.linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkAddress(DataTypes.unlinkAddressData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ADDRESS); - - LinkLogic.unlinkAddress( - vars.fromCharacterId, - vars.ethAddress, - vars.linkType, - _linklist, - _attachedLinklists[vars.fromCharacterId][vars.linkType] - ); - } - - /// @inheritdoc IWeb3Entry - function linkAnyUri(DataTypes.linkAnyUriData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_ANYURI); - - LinkLogic.linkAnyUri( - vars.fromCharacterId, - vars.toUri, - vars.linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkAnyUri(DataTypes.unlinkAnyUriData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.UNLINK_ANYURI); - - LinkLogic.unlinkAnyUri( - vars.fromCharacterId, - vars.toUri, - vars.linkType, - _linklist, - _attachedLinklists[vars.fromCharacterId][vars.linkType] - ); - } - - /// @inheritdoc IWeb3Entry - function linkLinklist(DataTypes.linkLinklistData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.LINK_LINKLIST); - - LinkLogic.linkLinklist( - vars.fromCharacterId, - vars.toLinkListId, - vars.linkType, - _linklist, - _attachedLinklists - ); - } - - /// @inheritdoc IWeb3Entry - function unlinkLinklist(DataTypes.unlinkLinklistData calldata vars) external override { - _validateCallerPermission(vars.fromCharacterId, OP.UNLINK_LINKLIST); - - LinkLogic.unlinkLinklist( - vars.fromCharacterId, - vars.toLinkListId, - vars.linkType, - _linklist, - _attachedLinklists[vars.fromCharacterId][vars.linkType] - ); - } - - /// @inheritdoc IWeb3Entry - function setLinkModule4Character( - DataTypes.setLinkModule4CharacterData calldata vars - ) external override { - _validateCallerPermission(vars.characterId, OP.SET_LINK_MODULE_FOR_CHARACTER); - - CharacterLogic.setCharacterLinkModule( - vars.characterId, - vars.linkModule, - vars.linkModuleInitData, - _characterById[vars.characterId] - ); - } - - /// @inheritdoc IWeb3Entry - function setLinkModule4Note(DataTypes.setLinkModule4NoteData calldata vars) external override { - _validateCallerPermission(vars.characterId, OP.SET_LINK_MODULE_FOR_NOTE); - _validateCallerPermission4Note(vars.characterId, vars.noteId); - _validateNoteExists(vars.characterId, vars.noteId); - _validateNoteNotLocked(vars.characterId, vars.noteId); - - PostLogic.setLinkModule4Note( - vars.characterId, - vars.noteId, - vars.linkModule, - vars.linkModuleInitData, - _noteByIdByCharacter - ); - } - - /// @inheritdoc IWeb3Entry - function mintNote( - DataTypes.MintNoteData calldata vars - ) external override returns (uint256 tokenId) { - _validateNoteExists(vars.characterId, vars.noteId); - - tokenId = PostLogic.mintNote( - vars.characterId, - vars.noteId, - vars.to, - vars.mintModuleData, - MINT_NFT_IMPL, - _noteByIdByCharacter - ); - } - - /// @inheritdoc IWeb3Entry - function setMintModule4Note(DataTypes.setMintModule4NoteData calldata vars) external override { - _validateCallerPermission(vars.characterId, OP.SET_MINT_MODULE_FOR_NOTE); - _validateNoteExists(vars.characterId, vars.noteId); - _validateNoteNotLocked(vars.characterId, vars.noteId); - - PostLogic.setMintModule4Note( - vars.characterId, - vars.noteId, - vars.mintModule, - vars.mintModuleInitData, - _noteByIdByCharacter - ); - } - - /// @inheritdoc IWeb3Entry - function postNote( - DataTypes.PostNoteData calldata vars - ) external override returns (uint256 noteId) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE); - - noteId = _nextNoteId(vars.characterId); - PostLogic.postNoteWithLink(vars, noteId, 0, 0, "", _noteByIdByCharacter); - } - - /// @inheritdoc IWeb3Entry - function setNoteUri( - uint256 characterId, - uint256 noteId, - string calldata newUri - ) external override { - _validateCallerPermission4Note(characterId, noteId); - _validateNoteExists(characterId, noteId); - _validateNoteNotLocked(characterId, noteId); - - PostLogic.setNoteUri(characterId, noteId, newUri, _noteByIdByCharacter); - } - - /// @inheritdoc IWeb3Entry - function lockNote(uint256 characterId, uint256 noteId) external override { - _validateCallerPermission(characterId, OP.LOCK_NOTE); - _validateNoteExists(characterId, noteId); - - _noteByIdByCharacter[characterId][noteId].locked = true; - - emit Events.LockNote(characterId, noteId); - } - - /// @inheritdoc IWeb3Entry - function deleteNote(uint256 characterId, uint256 noteId) external override { - _validateCallerPermission(characterId, OP.DELETE_NOTE); - _validateNoteExists(characterId, noteId); - - _noteByIdByCharacter[characterId][noteId].deleted = true; - - emit Events.DeleteNote(characterId, noteId); - } - - /// @inheritdoc IWeb3Entry - function postNote4Character( - DataTypes.PostNoteData calldata vars, - uint256 toCharacterId - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_CHARACTER); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_CHARACTER; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = bytes32(toCharacterId); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(toCharacterId), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function postNote4Address( - DataTypes.PostNoteData calldata vars, - address ethAddress - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ADDRESS); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ADDRESS; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = bytes32(uint256(uint160(ethAddress))); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(ethAddress), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function postNote4Linklist( - DataTypes.PostNoteData calldata vars, - uint256 toLinklistId - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_LINKLIST); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_LINKLIST; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = bytes32(toLinklistId); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(toLinklistId), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function postNote4Note( - DataTypes.PostNoteData calldata vars, - DataTypes.NoteStruct calldata note - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_NOTE); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_NOTE; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = ILinklist(_linklist).addLinkingNote(0, note.characterId, note.noteId); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(note.characterId, note.noteId), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function postNote4ERC721( - DataTypes.PostNoteData calldata vars, - DataTypes.ERC721Struct calldata erc721 - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ERC721); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ERC721; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = ILinklist(_linklist).addLinkingERC721( - 0, - erc721.tokenAddress, - erc721.erc721TokenId - ); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(erc721.tokenAddress, erc721.erc721TokenId), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function postNote4AnyUri( - DataTypes.PostNoteData calldata vars, - string calldata uri - ) external override returns (uint256) { - _validateCallerPermission(vars.characterId, OP.POST_NOTE_FOR_ANYURI); - - bytes32 linkItemType = Constants.LINK_ITEM_TYPE_ANYURI; - uint256 noteId = _nextNoteId(vars.characterId); - bytes32 linkKey = ILinklist(_linklist).addLinkingAnyUri(0, uri); - - PostLogic.postNoteWithLink( - vars, - noteId, - linkItemType, - linkKey, - abi.encodePacked(uri), - _noteByIdByCharacter - ); - - return noteId; - } - - /// @inheritdoc IWeb3Entry - function burnLinklist(uint256 linklistId) external override { - // only the owner of the character can burn the linklist through web3Entry contract - uint256 characterId = ILinklist(_linklist).getOwnerCharacterId(linklistId); - _validateCallerIsCharacterOwner(characterId); - - LinklistLogic.burnLinklist(characterId, linklistId, _linklist, _attachedLinklists); - } - - /// @inheritdoc IWeb3Entry - function getOperators(uint256 characterId) external view override returns (address[] memory) { - return _operatorsByCharacter[characterId].values(); - } - - /// @inheritdoc IWeb3Entry - function getOperatorPermissions( - uint256 characterId, - address operator - ) external view override returns (uint256) { - return _operatorsPermissionBitMap[characterId][operator]; - } - - /// @inheritdoc IWeb3Entry - function getOperators4Note( - uint256 characterId, - uint256 noteId - ) external view override returns (address[] memory blocklist, address[] memory allowlist) { - blocklist = _operators4Note[characterId][noteId].blocklist.values(); - allowlist = _operators4Note[characterId][noteId].allowlist.values(); - } - - /// @inheritdoc IWeb3Entry - function isOperatorAllowedForNote( - uint256 characterId, - uint256 noteId, - address operator - ) external view override returns (bool) { - return _isOperatorAllowedForNote(characterId, noteId, operator); - } - - /// @inheritdoc IWeb3Entry - function getPrimaryCharacterId(address account) external view override returns (uint256) { - return _primaryCharacterByAddress[account]; - } - - /// @inheritdoc IWeb3Entry - function isPrimaryCharacter(uint256 characterId) external view override returns (bool) { - address account = ownerOf(characterId); - return characterId == _primaryCharacterByAddress[account]; - } - - /// @inheritdoc IWeb3Entry - function getCharacter( - uint256 characterId - ) external view override onlyExistingToken(characterId) returns (DataTypes.Character memory) { - return _characterById[characterId]; - } - - /// @inheritdoc IWeb3Entry - function getCharacterByHandle( - string calldata handle - ) external view override returns (DataTypes.Character memory) { - bytes32 handleHash = keccak256(bytes(handle)); - uint256 characterId = _characterIdByHandleHash[handleHash]; - return _characterById[characterId]; - } - - /// @inheritdoc IWeb3Entry - function getHandle( - uint256 characterId - ) external view override onlyExistingToken(characterId) returns (string memory) { - return _characterById[characterId].handle; - } - - /// @inheritdoc IWeb3Entry - function getCharacterUri(uint256 characterId) external view override returns (string memory) { - return tokenURI(characterId); - } - - /// @inheritdoc IWeb3Entry - function getNote( - uint256 characterId, - uint256 noteId - ) external view override returns (DataTypes.Note memory) { - return _noteByIdByCharacter[characterId][noteId]; - } - - /// @inheritdoc IWeb3Entry - function getLinklistUri(uint256 tokenId) external view override returns (string memory) { - return ILinklist(_linklist).Uri(tokenId); - } - - /// @inheritdoc IWeb3Entry - function getLinklistId( - uint256 characterId, - bytes32 linkType - ) external view override returns (uint256) { - return _attachedLinklists[characterId][linkType]; - } - - /// @inheritdoc IWeb3Entry - function getLinklistType(uint256 linkListId) external view override returns (bytes32) { - return ILinklist(_linklist).getLinkType(linkListId); - } - - /// @inheritdoc IWeb3Entry - function getLinklistContract() external view override returns (address) { - return _linklist; - } - - /// @inheritdoc IWeb3Entry - function getDomainSeparator() external view override returns (bytes32) { - return _calculateDomainSeparator(); - } - - /// @inheritdoc IWeb3Entry - function nonces(address owner) external view override returns (uint256) { - return _sigNonces[owner]; - } - - /// @inheritdoc IWeb3Entry - function getRevision() external pure override returns (uint256) { - return REVISION; - } - - /** - * @notice Burns a web3Entry character nft. - * @param tokenId The token ID to burn. - */ - function burn(uint256 tokenId) public virtual override { - // clear handle - bytes32 handleHash = keccak256(bytes(_characterById[tokenId].handle)); - _characterIdByHandleHash[handleHash] = 0; - - // clear character - delete _characterById[tokenId]; - - // burn token - super.burn(tokenId); - } - - /** - * @notice Returns the associated URI with a given character. - * @param characterId The character ID to query. - * @return The token URI. - */ - function tokenURI( - uint256 characterId - ) public view override onlyExistingToken(characterId) returns (string memory) { - return _characterById[characterId].uri; - } - - function _createCharacter( - DataTypes.CreateCharacterData memory vars, - bool validateHandle - ) internal returns (uint256 characterId) { - // check if the handle exists - _checkHandleExists(keccak256(bytes(vars.handle))); - - // check if the handle is valid - if (validateHandle) { - _validateHandle(vars.handle); - } - - characterId = ++_characterCounter; - // mint character nft - _safeMint(vars.to, characterId); - - CharacterLogic.createCharacter( - vars.to, - vars.handle, - vars.uri, - vars.linkModule, - vars.linkModuleInitData, - characterId, - _characterIdByHandleHash, - _characterById - ); - } - - /** - * @dev Operators will be reset to blank before the characters are transferred in order to grant the - * whole control power to receivers of character transfers. - * If character is transferred from newbieVilla contract, don't clear operators. - * - * Permissions4Note is left unset, because permissions for notes are always stricter than default. - */ - function _beforeTokenTransfer( - address from, - address to, - uint256 tokenId - ) internal virtual override { - // clear operators if character is transferred from non-newbieVilla contract - if (from != _newbieVilla) { - // clear operators - uint256 len = _operatorsByCharacter[tokenId].length(); - address[] memory operators = _operatorsByCharacter[tokenId].values(); - for (uint256 i = 0; i < len; i++) { - _clearOperator(tokenId, operators[i]); - } - - // reset if `tokenId` is primary character of `from` account - if (_primaryCharacterByAddress[from] == tokenId) { - _primaryCharacterByAddress[from] = 0; - } - } - - super._beforeTokenTransfer(from, to, tokenId); - } - - function _afterTokenTransfer( - address from, - address to, - uint256 tokenId - ) internal virtual override { - // set primary character if `to` account has no primary character - if (_primaryCharacterByAddress[to] == 0) { - _primaryCharacterByAddress[to] = tokenId; - } - - super._afterTokenTransfer(from, to, tokenId); - } - - function _nextNoteId(uint256 characterId) internal returns (uint256) { - return ++_characterById[characterId].noteCount; - } - - function _clearOperator(uint256 tokenId, address operator) internal { - delete _operatorsPermissionBitMap[tokenId][operator]; - // slither-disable-next-line unused-return - _operatorsByCharacter[tokenId].remove(operator); - } - - function _grantOperatorPermissions( - uint256 characterId, - address operator, - uint256 permissionBitMap - ) internal { - OperatorLogic.grantOperatorPermissions( - characterId, - operator, - permissionBitMap, - _operatorsByCharacter, - _operatorsPermissionBitMap - ); - } - - function _isOperatorAllowedForNote( - uint256 characterId, - uint256 noteId, - address operator - ) internal view returns (bool) { - DataTypes.Operators4Note storage op = _operators4Note[characterId][noteId]; - - // check blocklist - if (op.blocklist.contains(operator)) { - return false; - } - // check allowlist - if (op.allowlist.contains(operator)) { - return true; - } - // check character operator permission - return _checkBit(_operatorsPermissionBitMap[characterId][operator], OP.SET_NOTE_URI); - } - - // check if the handle exists - function _checkHandleExists(bytes32 handleHash) internal view { - if (_characterIdByHandleHash[handleHash] != 0) revert ErrHandleExists(); - } - - function _validateCallerIsCharacterOwner(uint256 characterId) internal view { - address owner = ownerOf(characterId); - - // tx.origin is character owner, and msg.sender is periphery - // solhint-disable-next-line avoid-tx-origin - if (msg.sender == _periphery && tx.origin == owner) { - return; - } - - // msg.sender is character owner - if (msg.sender == owner) { - return; - } - - revert ErrNotCharacterOwner(); - } - - function _validateCallerPermission(uint256 characterId, uint256 permissionId) internal view { - // check character owner - if (_callerIsCharacterOwner(characterId)) { - return; - } - - // check operator permission for tx.origin - if (msg.sender == _periphery) { - // solhint-disable-next-line avoid-tx-origin - if (_checkBit(_operatorsPermissionBitMap[characterId][tx.origin], permissionId)) { - return; - } - } - - // check operator permission for msg.sender - if (_checkBit(_operatorsPermissionBitMap[characterId][msg.sender], permissionId)) { - return; - } - - revert ErrNotEnoughPermission(); - } - - function _callerIsCharacterOwner(uint256 characterId) internal view returns (bool) { - address owner = ownerOf(characterId); - - if (msg.sender == owner) { - // caller is character owner - return true; - } - - // solhint-disable-next-line avoid-tx-origin - if (msg.sender == _periphery && tx.origin == owner) { - // caller is periphery, and tx.origin is character owner - return true; - } - - return false; - } - - function _validateCallerPermission4Note(uint256 characterId, uint256 noteId) internal view { - // check character owner - if (_callerIsCharacterOwner(characterId)) { - return; - } - - // check note permission for tx.origin - if (msg.sender == _periphery) { - // solhint-disable-next-line avoid-tx-origin - if (_isOperatorAllowedForNote(characterId, noteId, tx.origin)) { - return; - } - } - - // check note permission for caller - if (_isOperatorAllowedForNote(characterId, noteId, msg.sender)) { - return; - } - - revert ErrNotEnoughPermissionForThisNote(); - } - - function _validateCharacterExists(uint256 characterId) internal view { - if (!_exists(characterId)) revert ErrCharacterNotExists(characterId); - } - - function _validateNoteExists(uint256 characterId, uint256 noteId) internal view { - if (_noteByIdByCharacter[characterId][noteId].deleted) revert ErrNoteIsDeleted(); - if (noteId > _characterById[characterId].noteCount) revert ErrNoteNotExists(); - } - - function _validateNoteNotLocked(uint256 characterId, uint256 noteId) internal view { - if (_noteByIdByCharacter[characterId][noteId].locked) revert ErrNoteLocked(); - } - - /** - * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. - */ - function _calculateDomainSeparator() internal view returns (bytes32) { - return - keccak256( - abi.encode( - EIP712_DOMAIN_TYPEHASH, - keccak256(bytes(name())), - 1, - block.chainid, - address(this) - ) - ); - } - - /** - * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. - */ - function _validateRecoveredAddress( - bytes32 digest, - address expectedAddress, - DataTypes.EIP712Signature calldata sig - ) internal view { - // slither-disable-next-line timestamp - if (sig.deadline < block.timestamp) revert ErrSignatureExpired(); - address recoveredAddress = ecrecover(digest, sig.v, sig.r, sig.s); - if (recoveredAddress == address(0) || recoveredAddress != expectedAddress) - revert ErrSignatureInvalid(); - } - - function _validateHandle(string memory handle) internal pure { - bytes memory byteHandle = bytes(handle); - uint256 len = byteHandle.length; - if (len > Constants.MAX_HANDLE_LENGTH || len < Constants.MIN_HANDLE_LENGTH) - revert ErrHandleLengthInvalid(); - - for (uint256 i = 0; i < len; ) { - _validateChar(byteHandle[i]); - - unchecked { - ++i; - } - } - } - - function _validateChar(bytes1 c) internal pure { - // char range: [0,9][a,z][-][_] - if ((c < "0" || c > "z" || (c > "9" && c < "a")) && c != "-" && c != "_") - revert ErrHandleContainsInvalidCharacters(); - } - - /** - * @dev _checkBit checks if the value of the i'th bit of x is 1 - */ - function _checkBit(uint256 x, uint256 i) internal pure returns (bool) { - return (x >> i) & 1 == 1; - } - - /** - * @dev _addressToHexString converts an address to its ASCII `string hexadecimal representation. - */ - function _addressToHexString(address addr) internal pure returns (string memory) { - bytes16 symbols = "0123456789abcdef"; - uint256 value = uint256(uint160(addr)); - - bytes memory buffer = new bytes(42); - buffer[0] = "0"; - buffer[1] = "x"; - for (uint256 i = 41; i > 1; ) { - buffer[i] = symbols[value & 0xf]; - value >>= 4; - - unchecked { - --i; - } - } - return string(buffer); - } -} diff --git a/contracts/base/LinklistBase.sol b/contracts/base/LinklistBase.sol index e80ab5998..8455f425d 100644 --- a/contracts/base/LinklistBase.sol +++ b/contracts/base/LinklistBase.sol @@ -2,21 +2,68 @@ pragma solidity 0.8.18; -import {ERC721} from "./ERC721.sol"; import {Events} from "../libraries/Events.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; + +abstract contract LinklistBase is ERC165 { + // Token name + string private _name; + + // Token symbol + string private _symbol; -abstract contract LinklistBase is ERC721 { /** * @dev For compatibility with previous ERC721Enumerable, we need to keep the unused slots for upgradeability. */ + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // unused slot 6 mapping(uint256 => uint256) private _ownedTokensIndex; // unused slot 7 uint256[] private _allTokens; // unused slot 8 mapping(uint256 => uint256) private _allTokensIndex; // unused slot 9 - function _initialize(string calldata name, string calldata symbol) internal { - ERC721.__ERC721_Init(name, symbol); + function _initialize(string calldata name_, string calldata symbol_) internal { + _name = name_; + _symbol = symbol_; + + emit Events.BaseInitialized(name_, symbol_, block.timestamp); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } - emit Events.BaseInitialized(name, symbol, block.timestamp); + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view returns (string memory) { + return _symbol; } } diff --git a/contracts/interfaces/ILinklist.sol b/contracts/interfaces/ILinklist.sol index 1081bcc55..223cc0747 100644 --- a/contracts/interfaces/ILinklist.sol +++ b/contracts/interfaces/ILinklist.sol @@ -312,7 +312,6 @@ interface ILinklist { * @param tokenId The token ID of linklist to check. * @return The URI of the linklist NFT. */ - // slither-disable-next-line naming-convention function Uri(uint256 tokenId) external view returns (string memory); // solhint-disable func-name-mixedcase /** @@ -322,16 +321,30 @@ interface ILinklist { */ function characterOwnerOf(uint256 tokenId) external view returns (uint256); + /** + * @notice Returns the total supply of the Linklist NFTs. + * @return The total supply of the Linklist NFTs. + */ + function totalSupply() external view returns (uint256); + /** * @notice Returns the balance of the character. * @param characterId The character ID to check. - * @return The balance of the character. + * @return uint256 The balance of the character. */ function balanceOf(uint256 characterId) external view returns (uint256); /** - * @notice Returns the total supply of the Linklist NFTs. - * @return The total supply of the Linklist NFTs. + * @notice Returns the balance of the address. + * @param account The address to check. + * @return balance The balance of the address. */ - function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256 balance); + + /** + * @notice Returns the owner of the `tokenId` token. + * @param tokenId The token ID to check. + * @return The owner of the `tokenId` token. + */ + function ownerOf(uint256 tokenId) external view returns (address); } diff --git a/contracts/interfaces/ITipsWithConfig.sol b/contracts/interfaces/ITipsWithConfig.sol index b6526f227..377326b75 100644 --- a/contracts/interfaces/ITipsWithConfig.sol +++ b/contracts/interfaces/ITipsWithConfig.sol @@ -2,8 +2,6 @@ pragma solidity 0.8.18; -import {DataTypes} from "../libraries/DataTypes.sol"; - /** * @title ITipsWithConfig * @notice This is the interface for the TipsWithConfig contract. @@ -89,8 +87,9 @@ interface ITipsWithConfig { * Emits a {CollectTips4Character} event if collects successfully. * @dev It will transfer all unredeemed token from the `fromCharacter` to the `toCharacter`. * @param tipConfigId The tip config ID. + * @return collectedAmount The amount of token collected. */ - function collectTips4Character(uint256 tipConfigId) external; + function collectTips4Character(uint256 tipConfigId) external returns (uint256 collectedAmount); /** * @notice Returns the fee percentage of specific . diff --git a/contracts/interfaces/IWeb3Entry.sol b/contracts/interfaces/IWeb3Entry.sol index 34c2d86dc..d8e2eaaf3 100644 --- a/contracts/interfaces/IWeb3Entry.sol +++ b/contracts/interfaces/IWeb3Entry.sol @@ -62,7 +62,7 @@ interface IWeb3Entry { /** * @notice Sets a given character as primary. - * @dev Owner permission only. + * @dev Only character owner can call this function. * @param characterId The character id to to be set. */ function setPrimaryCharacterId(uint256 characterId) external; @@ -86,14 +86,14 @@ interface IWeb3Entry { * @param characterId ID of your character that you want to authorize. * @param operator Address to grant operator permissions to. * @param permissionBitMap Bitmap used for finer grained operator permissions controls. - * @param sig The EIP712Signature struct containing the character owner's signature. + * @param signature The EIP712Signature struct containing the character owner's signature. * @dev Every bit in permissionBitMap stands for a corresponding method in Web3Entry. more details in OP.sol. */ function grantOperatorPermissionsWithSig( uint256 characterId, address operator, uint256 permissionBitMap, - DataTypes.EIP712Signature calldata sig + DataTypes.EIP712Signature calldata signature ) external; /** @@ -344,11 +344,12 @@ interface IWeb3Entry { * `mintModule`: The address of mint module to set for the new post.
* `mintModuleInitData`: The data passed to the mint module to init, if any.
* @param toCharacterId The target character ID. + * @return noteId The note ID of the new post. */ function postNote4Character( DataTypes.PostNoteData calldata vars, uint256 toCharacterId - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Posts a note for a given address. @@ -360,11 +361,12 @@ interface IWeb3Entry { * `mintModule`: The address of mint module to set for the new post.
* `mintModuleInitData`: The data passed to the mint module to init, if any.
* @param ethAddress The target address. + * @return noteId The note ID of the new post. */ function postNote4Address( DataTypes.PostNoteData calldata vars, address ethAddress - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Posts a note for a given linklist. @@ -376,11 +378,12 @@ interface IWeb3Entry { * `mintModule`: The address of mint module to set for the new post.
* `mintModuleInitData`: The data passed to the mint module to init, if any.
* @param toLinklistId The target linklist. + * @return noteId The note ID of the new post. */ function postNote4Linklist( DataTypes.PostNoteData calldata vars, uint256 toLinklistId - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Posts a note for a given note. @@ -394,11 +397,12 @@ interface IWeb3Entry { * @param note The target note struct containing the parameters:
* `characterId`: The character ID of target note.
* `noteId`: The note ID of target note. + * @return noteId The note ID of the new post. */ function postNote4Note( DataTypes.PostNoteData calldata vars, DataTypes.NoteStruct calldata note - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Posts a note for a given ERC721. @@ -412,11 +416,12 @@ interface IWeb3Entry { * @param erc721 The target ERC721 struct containing the parameters:
* `tokenAddress`: The token address of target ERC721.
* `erc721TokenId`: The token ID of target ERC721. + * @return noteId The note ID of the new post. */ function postNote4ERC721( DataTypes.PostNoteData calldata vars, DataTypes.ERC721Struct calldata erc721 - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Posts a note for a given uri. @@ -428,11 +433,12 @@ interface IWeb3Entry { * `mintModule`: The address of mint module to set for the new post.
* `mintModuleInitData`: The data passed to the mint module to init, if any.
* @param uri The target uri(could be an url link). + * @return noteId The note ID of the new post. */ function postNote4AnyUri( DataTypes.PostNoteData calldata vars, string calldata uri - ) external returns (uint256); + ) external returns (uint256 noteId); /** * @notice Burns a linklist NFT. diff --git a/contracts/libraries/CharacterLogic.sol b/contracts/libraries/CharacterLib.sol similarity index 52% rename from contracts/libraries/CharacterLogic.sol rename to contracts/libraries/CharacterLib.sol index 76eb258a3..c04a5944e 100644 --- a/contracts/libraries/CharacterLogic.sol +++ b/contracts/libraries/CharacterLib.sol @@ -4,20 +4,23 @@ pragma solidity 0.8.18; import {DataTypes} from "./DataTypes.sol"; import {Events} from "./Events.sol"; +import {StorageLib} from "./StorageLib.sol"; +import {ValidationLib} from "./ValidationLib.sol"; import {ILinkModule4Character} from "../interfaces/ILinkModule4Character.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -library CharacterLogic { +library CharacterLib { using EnumerableSet for EnumerableSet.Bytes32Set; /** - * @notice Creates a character. - * @param to The address to mint the character to. - * @param handle The handle to set for the new character. - * @param uri The URI to set for the new character’s metadata. - * @param linkModule The link module to set for the new character or the zero address. - * @param linkModuleInitData Arbitrary data to be decoded in the link module for initialization. - * @param characterId The ID of the new character. + * @notice Creates a character. + * @param to The address to mint the character to. + * @param handle The handle to set for the new character. + * @param uri The URI to set for the new character’s metadata. + * @param linkModule The link module to set for the new character or the zero address. + * @param linkModuleInitData Arbitrary data to be decoded in the link module for initialization. + * @param characterId The ID of the new character. + * @param validateHandle Whether to validate the handle or not. */ function createCharacter( address to, @@ -26,19 +29,25 @@ library CharacterLogic { address linkModule, bytes memory linkModuleInitData, uint256 characterId, - mapping(bytes32 => uint256) storage _characterIdByHandleHash, - mapping(uint256 => DataTypes.Character) storage _characterById + bool validateHandle ) external { + if (validateHandle) { + ValidationLib.validateHandle(handle); + } bytes32 handleHash = keccak256(bytes(handle)); - _characterIdByHandleHash[handleHash] = characterId; + // check if the handle exists + ValidationLib.validateHandleNotExists(handleHash); + StorageLib.characterIdByHandleHash()[handleHash] = characterId; - _characterById[characterId].characterId = characterId; - _characterById[characterId].handle = handle; - _characterById[characterId].uri = uri; + // save character + DataTypes.Character storage _character = StorageLib.getCharacter(characterId); + _character.characterId = characterId; + _character.handle = handle; + _character.uri = uri; // init link module if (linkModule != address(0)) { - _characterById[characterId].linkModule = linkModule; + _character.linkModule = linkModule; ILinkModule4Character(linkModule).initializeLinkModule(characterId, linkModuleInitData); } @@ -51,13 +60,8 @@ library CharacterLogic { * @param characterId The character ID to set social token for. * @param tokenAddress Token address to be set. */ - function setSocialToken( - uint256 characterId, - address tokenAddress, - mapping(uint256 => DataTypes.Character) storage _characterById - ) external { - _characterById[characterId].socialToken = tokenAddress; - + function setSocialToken(uint256 characterId, address tokenAddress) external { + StorageLib.getCharacter(characterId).socialToken = tokenAddress; emit Events.SetSocialToken(msg.sender, characterId, tokenAddress); } @@ -70,10 +74,9 @@ library CharacterLogic { function setCharacterLinkModule( uint256 characterId, address linkModule, - bytes calldata linkModuleInitData, - DataTypes.Character storage _character + bytes calldata linkModuleInitData ) external { - _character.linkModule = linkModule; + StorageLib.getCharacter(characterId).linkModule = linkModule; bytes memory returnData = ""; if (linkModule != address(0)) { @@ -95,22 +98,24 @@ library CharacterLogic { * @param characterId The character ID to set new handle for. * @param newHandle New handle to set. */ - function setHandle( - uint256 characterId, - string calldata newHandle, - mapping(bytes32 => uint256) storage _characterIdByHandleHash, - mapping(uint256 => DataTypes.Character) storage _characterById - ) external { + function setHandle(uint256 characterId, string calldata newHandle) external { + ValidationLib.validateHandleNotExists(_handleHash(newHandle)); + ValidationLib.validateHandle(newHandle); + // remove old handle - string memory oldHandle = _characterById[characterId].handle; - bytes32 oldHandleHash = keccak256(bytes(oldHandle)); - delete _characterIdByHandleHash[oldHandleHash]; + string memory oldHandle = StorageLib.getCharacter(characterId).handle; + bytes32 oldHandleHash = _handleHash(oldHandle); + delete StorageLib.characterIdByHandleHash()[oldHandleHash]; // set new handle - bytes32 handleHash = keccak256(bytes(newHandle)); - _characterIdByHandleHash[handleHash] = characterId; - _characterById[characterId].handle = newHandle; + bytes32 handleHash = _handleHash(newHandle); + StorageLib.characterIdByHandleHash()[handleHash] = characterId; + StorageLib.getCharacter(characterId).handle = newHandle; emit Events.SetHandle(msg.sender, characterId, newHandle); } + + function _handleHash(string memory handle) internal pure returns (bytes32) { + return keccak256(bytes(handle)); + } } diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index ae8ebd0a4..e716ead2b 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -245,12 +245,14 @@ library DataTypes { /** * @dev A struct containing the necessary information to reconstruct an EIP-712 typed data signature. + * @param signer The address of the signer. * @param v The signature's recovery parameter. * @param r The signature's r parameter. * @param s The signature's s parameter * @param deadline The signature's deadline. */ struct EIP712Signature { + address signer; uint8 v; bytes32 r; bytes32 s; diff --git a/contracts/libraries/LinkLogic.sol b/contracts/libraries/LinkLib.sol similarity index 80% rename from contracts/libraries/LinkLogic.sol rename to contracts/libraries/LinkLib.sol index 93a9eac43..3ececc713 100644 --- a/contracts/libraries/LinkLogic.sol +++ b/contracts/libraries/LinkLib.sol @@ -3,13 +3,14 @@ pragma solidity 0.8.18; import {Events} from "./Events.sol"; +import {StorageLib} from "./StorageLib.sol"; import {ILinklist} from "../interfaces/ILinklist.sol"; import {ILinkModule4Character} from "../interfaces/ILinkModule4Character.sol"; import {ILinkModule4Note} from "../interfaces/ILinkModule4Note.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -library LinkLogic { +library LinkLib { using EnumerableSet for EnumerableSet.Bytes32Set; /** @@ -19,24 +20,22 @@ library LinkLogic { * @param linkType linkType, like “follow”. * @param data The data to pass to the link module, if any. * @param linklist The linklist contract address. - * @param linkModule The linkModule address of the character to link. */ function linkCharacter( uint256 fromCharacterId, uint256 toCharacterId, bytes32 linkType, bytes memory data, - address linklist, - address linkModule, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - address linker = IERC721(address(this)).ownerOf(fromCharacterId); - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + address linker = _ownerOf(fromCharacterId); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingCharacterId(linklistId, toCharacterId); // process link module + address linkModule = StorageLib.getCharacter(toCharacterId).linkModule; if (linkModule != address(0)) { try ILinkModule4Character(linkModule).processLink(linker, toCharacterId, data) @@ -52,16 +51,15 @@ library LinkLogic { * @param toCharacterId The character ID to be unlinked. * @param linkType linkType, like “follow”. * @param linklist The linklist contract address. - * @param linklistId The ID of the linklist to unlink. */ function unlinkCharacter( uint256 fromCharacterId, uint256 toCharacterId, bytes32 linkType, - address linklist, - uint256 linklistId + address linklist ) external { - address linker = IERC721(address(this)).ownerOf(fromCharacterId); + address linker = _ownerOf(fromCharacterId); + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); // remove from link list ILinklist(linklist).removeLinkingCharacterId(linklistId, toCharacterId); @@ -76,7 +74,6 @@ library LinkLogic { * @param linkType The linkType, like “follow”. * @param data The data to pass to the link module, if any. * @param linklist The linklist contract address. - * @param linkModule The linkModule address of the note to link */ function linkNote( uint256 fromCharacterId, @@ -84,17 +81,16 @@ library LinkLogic { uint256 toNoteId, bytes32 linkType, bytes calldata data, - address linklist, - address linkModule, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - address linker = IERC721(address(this)).ownerOf(fromCharacterId); - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + address linker = _ownerOf(fromCharacterId); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingNote(linklistId, toCharacterId, toNoteId); // process link + address linkModule = StorageLib.getNote(toCharacterId, toNoteId).linkModule; if (linkModule != address(0)) { try ILinkModule4Note(linkModule).processLink(linker, toCharacterId, toNoteId, data) @@ -117,14 +113,11 @@ library LinkLogic { uint256 toCharacterId, uint256 toNoteId, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { // do note check note // _validateNoteExists(vars.toCharacterId, vars.toNoteId); - - uint256 linklistId = _attachedLinklists[fromCharacterId][linkType]; - + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); // remove from link list ILinklist(linklist).removeLinkingNote(linklistId, toCharacterId, toNoteId); @@ -142,10 +135,9 @@ library LinkLogic { uint256 fromCharacterId, uint256 toLinkListId, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingLinklistId(linklistId, toLinkListId); @@ -159,16 +151,15 @@ library LinkLogic { * @param toLinkListId The linklist if to unlink. * @param linkType LinkType, like “follow”. * @param linklist The linklist contract address. - * @param linklistId The ID of the linklist to unlink. */ function unlinkLinklist( uint256 fromCharacterId, uint256 toLinkListId, bytes32 linkType, - address linklist, - uint256 linklistId + address linklist ) external { - // add to link list + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); + // remove `toLinkListId` from linklist ILinklist(linklist).removeLinkingLinklistId(linklistId, toLinkListId); emit Events.UnlinkLinklist(fromCharacterId, toLinkListId, linkType, linklistId); @@ -187,10 +178,9 @@ library LinkLogic { address tokenAddress, uint256 tokenId, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingERC721(linklistId, tokenAddress, tokenId); @@ -205,17 +195,17 @@ library LinkLogic { * @param tokenId The token ID of ERC721 to unlink. * @param linkType LinkType, like “follow”. * @param linklist The linklist contract address. - * @param linklistId The ID of the linklist to unlink. */ function unlinkERC721( uint256 fromCharacterId, address tokenAddress, uint256 tokenId, bytes32 linkType, - address linklist, - uint256 linklistId + address linklist ) external { - // remove from link list + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); + + // remove from linklist ILinklist(linklist).removeLinkingERC721(linklistId, tokenAddress, tokenId); emit Events.UnlinkERC721(fromCharacterId, tokenAddress, tokenId, linkType, linklistId); @@ -232,10 +222,9 @@ library LinkLogic { uint256 fromCharacterId, address ethAddress, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingAddress(linklistId, ethAddress); @@ -249,16 +238,15 @@ library LinkLogic { * @param ethAddress The address to unlink. * @param linkType LinkType, like “follow”. * @param linklist The linklist contract address. - * @param linklistId The ID of the linklist to unlink. */ function unlinkAddress( uint256 fromCharacterId, address ethAddress, bytes32 linkType, - address linklist, - uint256 linklistId + address linklist ) external { - // remove from link list + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); + // remove from linklist ILinklist(linklist).removeLinkingAddress(linklistId, ethAddress); emit Events.UnlinkAddress(fromCharacterId, ethAddress, linkType); @@ -275,10 +263,9 @@ library LinkLogic { uint256 fromCharacterId, string calldata toUri, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { - uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist, _attachedLinklists); + uint256 linklistId = _mintLinklist(fromCharacterId, linkType, linklist); // add to link list ILinklist(linklist).addLinkingAnyUri(linklistId, toUri); @@ -292,16 +279,15 @@ library LinkLogic { * @param toUri The uri to unlink. * @param linkType LinkType, like “follow”. * @param linklist The linklist contract address. - * @param linklistId The ID of the linklist to unlink. */ function unlinkAnyUri( uint256 fromCharacterId, string calldata toUri, bytes32 linkType, - address linklist, - uint256 linklistId + address linklist ) external { - // remove from link list + uint256 linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); + // remove from linklist ILinklist(linklist).removeLinkingAnyUri(linklistId, toUri); emit Events.UnlinkAnyUri(fromCharacterId, toUri, linkType); @@ -314,17 +300,20 @@ library LinkLogic { function _mintLinklist( uint256 fromCharacterId, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) internal returns (uint256 linklistId) { - linklistId = _attachedLinklists[fromCharacterId][linkType]; + linklistId = StorageLib.getAttachedLinklistId(fromCharacterId, linkType); if (linklistId == 0) { // mint linkList nft linklistId = ILinklist(linklist).mint(fromCharacterId, linkType); // attach linkList - _attachedLinklists[fromCharacterId][linkType] = linklistId; + StorageLib.setAttachedLinklistId(fromCharacterId, linkType, linklistId); emit Events.AttachLinklist(linklistId, fromCharacterId, linkType); } } + + function _ownerOf(uint256 characterId) internal view returns (address) { + return IERC721(address(this)).ownerOf(characterId); + } } diff --git a/contracts/libraries/LinklistLogic.sol b/contracts/libraries/LinklistLib.sol similarity index 65% rename from contracts/libraries/LinklistLogic.sol rename to contracts/libraries/LinklistLib.sol index 4827e2d20..bf3aed68b 100644 --- a/contracts/libraries/LinklistLogic.sol +++ b/contracts/libraries/LinklistLib.sol @@ -3,10 +3,11 @@ pragma solidity 0.8.18; import {Events} from "./Events.sol"; -import {ILinklist} from "../interfaces/ILinklist.sol"; import {ErrLinkTypeExists} from "./Error.sol"; +import {StorageLib} from "./StorageLib.sol"; +import {ILinklist} from "../interfaces/ILinklist.sol"; -library LinklistLogic { +library LinklistLib { function setLinklistUri(uint256 linklistId, string calldata uri, address linklist) external { ILinklist(linklist).setUri(linklistId, uri); } @@ -15,35 +16,29 @@ library LinklistLogic { uint256 characterId, uint256 linklistId, bytes32 linkType, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists + address linklist ) external { // check linklist exists - if (0 != _attachedLinklists[characterId][linkType]) + if (0 != StorageLib.getAttachedLinklistId(characterId, linkType)) revert ErrLinkTypeExists(characterId, linkType); // detach linklist bytes32 oldLinkType = ILinklist(linklist).getLinkType(linklistId); - delete _attachedLinklists[characterId][oldLinkType]; + StorageLib.deleteAttachedLinklistId(characterId, oldLinkType); emit Events.DetachLinklist(linklistId, characterId, oldLinkType); // attach linklist - _attachedLinklists[characterId][linkType] = linklistId; + StorageLib.setAttachedLinklistId(characterId, linkType, linklistId); emit Events.AttachLinklist(linklistId, characterId, linkType); // set linklist type ILinklist(linklist).setLinkType(linklistId, linkType); } - function burnLinklist( - uint256 characterId, - uint256 linklistId, - address linklist, - mapping(uint256 => mapping(bytes32 => uint256)) storage _attachedLinklists - ) external { - // delete _attachedLinklist + function burnLinklist(uint256 characterId, uint256 linklistId, address linklist) external { bytes32 linkType = ILinklist(linklist).getLinkType(linklistId); - delete _attachedLinklists[characterId][linkType]; + // detach linklist + StorageLib.deleteAttachedLinklistId(characterId, linkType); // burn linklist ILinklist(linklist).burn(linklistId); diff --git a/contracts/libraries/MetaTxLib.sol b/contracts/libraries/MetaTxLib.sol new file mode 100644 index 000000000..5350bfedc --- /dev/null +++ b/contracts/libraries/MetaTxLib.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +// solhint-disable private-vars-leading-underscore +pragma solidity 0.8.18; + +import {StorageLib} from "./StorageLib.sol"; +import {DataTypes} from "./DataTypes.sol"; +import {ErrSignatureInvalid, ErrSignatureExpired} from "./Error.sol"; +import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +library MetaTxLib { + // solhint-disable-next-line private-vars-leading-underscore, var-name-mixedcase + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + // solhint-disable-next-line private-vars-leading-underscore, var-name-mixedcase + bytes32 internal constant GRANT_OPERATOR_PERMISSIONS_WITH_SIG_TYPEHASH = + keccak256( // solhint-disable-next-line max-line-length + "grantOperatorPermissions(uint256 characterId,address operator,uint256 permissionBitMap,uint256 nonce,uint256 deadline)" + ); + // the `isValidSignature` function returns the bytes4 magic value 0x1626ba7e when function passes + bytes4 public constant EIP1271_MAGIC_VALUE = 0x1626ba7e; + + function validateGrantOperatorPermissionsSignature( + DataTypes.EIP712Signature calldata signature, + uint256 characterId, + address operator, + uint256 permissionBitMap + ) external { + bytes32 hashedMessage = keccak256( + abi.encode( + GRANT_OPERATOR_PERMISSIONS_WITH_SIG_TYPEHASH, + characterId, + operator, + permissionBitMap, + _getAndIncrementNonce(signature.signer), + signature.deadline + ) + ); + _validateRecoveredAddress( + ECDSA.toTypedDataHash(_calculateDomainSeparator(), hashedMessage), + signature + ); + } + + /** + * @dev This fetches a user's signing nonce and increments it, akin to `sigNonces++`. + */ + function _getAndIncrementNonce(address user) internal returns (uint256) { + unchecked { + return StorageLib.nonces()[user]++; + } + } + + /** + * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. + */ + function _calculateDomainSeparator() internal view returns (bytes32) { + return + keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes(IERC721Metadata(address(this)).name())), + 1, + block.chainid, + address(this) + ) + ); + } + + /** + * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. + */ + function _validateRecoveredAddress( + bytes32 digest, + DataTypes.EIP712Signature calldata signature + ) internal view { + // slither-disable-next-line timestamp + if (signature.deadline < block.timestamp) revert ErrSignatureExpired(); + + if (signature.signer.code.length != 0) { + bytes memory concatenatedSig = abi.encodePacked(signature.r, signature.s, signature.v); + if ( + IERC1271(signature.signer).isValidSignature(digest, concatenatedSig) != + EIP1271_MAGIC_VALUE + ) { + revert ErrSignatureInvalid(); + } + } else { + address recoveredAddress = ecrecover(digest, signature.v, signature.r, signature.s); + if (recoveredAddress == address(0) || recoveredAddress != signature.signer) { + revert ErrSignatureInvalid(); + } + } + } +} diff --git a/contracts/libraries/OperatorLogic.sol b/contracts/libraries/OperatorLib.sol similarity index 74% rename from contracts/libraries/OperatorLogic.sol rename to contracts/libraries/OperatorLib.sol index 335b3b626..45e27ec4b 100644 --- a/contracts/libraries/OperatorLogic.sol +++ b/contracts/libraries/OperatorLib.sol @@ -5,9 +5,10 @@ pragma solidity 0.8.18; import {Events} from "./Events.sol"; import {DataTypes} from "./DataTypes.sol"; import {OP} from "./OP.sol"; +import {StorageLib} from "./StorageLib.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -library OperatorLogic { +library OperatorLib { using EnumerableSet for EnumerableSet.AddressSet; /** @@ -19,18 +20,17 @@ library OperatorLogic { function grantOperatorPermissions( uint256 characterId, address operator, - uint256 permissionBitMap, - mapping(uint256 => EnumerableSet.AddressSet) storage _operatorsByCharacter, - mapping(uint256 => mapping(address => uint256)) storage _operatorsPermissionBitMap + uint256 permissionBitMap ) external { + EnumerableSet.AddressSet storage operators = StorageLib.operatorsByCharacter()[characterId]; if (permissionBitMap == 0) { - _operatorsByCharacter[characterId].remove(operator); + operators.remove(operator); } else { - _operatorsByCharacter[characterId].add(operator); + operators.add(operator); } uint256 bitmap = _bitmapFilter(permissionBitMap); - _operatorsPermissionBitMap[characterId][operator] = bitmap; + StorageLib.setOperatorsPermissionBitMap(characterId, operator, bitmap); emit Events.GrantOperatorPermissions(characterId, operator, bitmap); } @@ -45,11 +45,13 @@ library OperatorLogic { uint256 characterId, uint256 noteId, address[] calldata blocklist, - address[] calldata allowlist, - mapping(uint256 => mapping(uint256 => DataTypes.Operators4Note)) storage _operators4Note + address[] calldata allowlist ) external { - DataTypes.Operators4Note storage operators4Note = _operators4Note[characterId][noteId]; - // clear all iterms in blocklist and allowlist first + DataTypes.Operators4Note storage operators4Note = StorageLib.getOperators4Note( + characterId, + noteId + ); + // clear all items in blocklist and allowlist first _clearOperators4Note(operators4Note); // update blocklist and allowlist @@ -58,6 +60,21 @@ library OperatorLogic { emit Events.GrantOperators4Note(characterId, noteId, blocklist, allowlist); } + function clearOperators(uint256 characterId) external { + EnumerableSet.AddressSet storage _operators = StorageLib.operatorsByCharacter()[ + characterId + ]; + + // clear operators + uint256 len = _operators.length(); + address[] memory values = _operators.values(); + for (uint256 i = 0; i < len; i++) { + // clear permission bitmap + StorageLib.setOperatorsPermissionBitMap(characterId, values[i], 0); + _operators.remove(values[i]); + } + } + function _clearOperators4Note(DataTypes.Operators4Note storage operators4Note) internal { uint256 blocklistLength = operators4Note.blocklist.length(); for (uint256 i = blocklistLength; i > 0; ) { diff --git a/contracts/libraries/PostLogic.sol b/contracts/libraries/PostLib.sol similarity index 70% rename from contracts/libraries/PostLogic.sol rename to contracts/libraries/PostLib.sol index e5e2034ee..6483a8a7d 100644 --- a/contracts/libraries/PostLogic.sol +++ b/contracts/libraries/PostLib.sol @@ -2,15 +2,17 @@ // solhint-disable private-vars-leading-underscore pragma solidity 0.8.18; -import {DataTypes} from "./DataTypes.sol"; -import {Events} from "./Events.sol"; import {ILinkModule4Note} from "../interfaces/ILinkModule4Note.sol"; import {IMintModule4Note} from "../interfaces/IMintModule4Note.sol"; import {IMintNFT} from "../interfaces/IMintNFT.sol"; +import {StorageLib} from "./StorageLib.sol"; +import {ValidationLib} from "./ValidationLib.sol"; +import {DataTypes} from "./DataTypes.sol"; +import {Events} from "./Events.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -library PostLogic { +library PostLib { using Strings for uint256; function postNoteWithLink( @@ -18,38 +20,36 @@ library PostLogic { uint256 noteId, bytes32 linkItemType, bytes32 linkKey, - bytes calldata data, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + bytes calldata data ) external { - uint256 characterId = vars.characterId; - DataTypes.Note storage note = _noteByIdByCharacter[characterId][noteId]; + DataTypes.Note storage _note = StorageLib.getNote(vars.characterId, noteId); // save note - note.contentUri = vars.contentUri; + _note.contentUri = vars.contentUri; if (linkItemType != bytes32(0)) { - note.linkItemType = linkItemType; - note.linkKey = linkKey; + _note.linkItemType = linkItemType; + _note.linkKey = linkKey; } // init link module _setLinkModule4Note( - characterId, + vars.characterId, noteId, vars.linkModule, vars.linkModuleInitData, - _noteByIdByCharacter + _note ); // init mint module _setMintModule4Note( - characterId, + vars.characterId, noteId, vars.mintModule, vars.mintModuleInitData, - _noteByIdByCharacter + _note ); - emit Events.PostNote(characterId, noteId, linkKey, linkItemType, data); + emit Events.PostNote(vars.characterId, noteId, linkKey, linkItemType, data); } function mintNote( @@ -57,20 +57,19 @@ library PostLogic { uint256 noteId, address to, bytes calldata mintModuleData, - address mintNFTImpl, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + address mintNFTImpl ) external returns (uint256 tokenId) { - DataTypes.Note storage note = _noteByIdByCharacter[characterId][noteId]; - address mintNFT = note.mintNFT; + DataTypes.Note storage _note = StorageLib.getNote(characterId, noteId); + address mintNFT = _note.mintNFT; if (mintNFT == address(0)) { mintNFT = _deployMintNFT(characterId, noteId, mintNFTImpl); - note.mintNFT = mintNFT; + _note.mintNFT = mintNFT; } // mint nft tokenId = IMintNFT(mintNFT).mint(to); - address mintModule = note.mintModule; + address mintModule = _note.mintModule; if (mintModule != address(0)) { IMintModule4Note(mintModule).processMint(to, characterId, noteId, mintModuleData); } @@ -78,17 +77,29 @@ library PostLogic { emit Events.MintNote(to, characterId, noteId, mintNFT, tokenId); } - function setNoteUri( - uint256 characterId, - uint256 noteId, - string calldata newUri, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter - ) external { - _noteByIdByCharacter[characterId][noteId].contentUri = newUri; + function setNoteUri(uint256 characterId, uint256 noteId, string calldata newUri) external { + DataTypes.Note storage _note = StorageLib.getNote(characterId, noteId); + _note.contentUri = newUri; emit Events.SetNoteUri(characterId, noteId, newUri); } + function lockNote(uint256 characterId, uint256 noteId) external { + ValidationLib.validateNoteExists(characterId, noteId); + + StorageLib.getNote(characterId, noteId).locked = true; + + emit Events.LockNote(characterId, noteId); + } + + function deleteNote(uint256 characterId, uint256 noteId) external { + ValidationLib.validateNoteExists(characterId, noteId); + + StorageLib.getNote(characterId, noteId).deleted = true; + + emit Events.DeleteNote(characterId, noteId); + } + /** * @notice Sets link module for a given note. * @param characterId The character ID to set link module for. @@ -100,15 +111,17 @@ library PostLogic { uint256 characterId, uint256 noteId, address linkModule, - bytes calldata linkModuleInitData, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + bytes calldata linkModuleInitData ) external { + ValidationLib.validateNoteExists(characterId, noteId); + ValidationLib.validateNoteNotLocked(characterId, noteId); + _setLinkModule4Note( characterId, noteId, linkModule, linkModuleInitData, - _noteByIdByCharacter + StorageLib.getNote(characterId, noteId) ); } @@ -123,15 +136,14 @@ library PostLogic { uint256 characterId, uint256 noteId, address mintModule, - bytes calldata mintModuleInitData, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + bytes calldata mintModuleInitData ) external { _setMintModule4Note( characterId, noteId, mintModule, mintModuleInitData, - _noteByIdByCharacter + StorageLib.getNote(characterId, noteId) ); } @@ -158,10 +170,10 @@ library PostLogic { uint256 noteId, address linkModule, bytes calldata linkModuleInitData, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + DataTypes.Note storage _note ) internal { if (linkModule != address(0)) { - _noteByIdByCharacter[characterId][noteId].linkModule = linkModule; + _note.linkModule = linkModule; bytes memory returnData = ILinkModule4Note(linkModule).initializeLinkModule( characterId, @@ -184,10 +196,10 @@ library PostLogic { uint256 noteId, address mintModule, bytes calldata mintModuleInitData, - mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter + DataTypes.Note storage _note ) internal { if (mintModule != address(0)) { - _noteByIdByCharacter[characterId][noteId].mintModule = mintModule; + _note.mintModule = mintModule; bytes memory returnData = IMintModule4Note(mintModule).initializeMintModule( characterId, diff --git a/contracts/libraries/StorageLib.sol b/contracts/libraries/StorageLib.sol new file mode 100644 index 000000000..94c02ea70 --- /dev/null +++ b/contracts/libraries/StorageLib.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// solhint-disable no-inline-assembly,private-vars-leading-underscore +pragma solidity 0.8.18; + +import {DataTypes} from "./DataTypes.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +library StorageLib { + using EnumerableSet for EnumerableSet.AddressSet; + + uint256 public constant CHARACTERS_MAPPING_SLOT = 10; + uint256 public constant CHARACTER_ID_BY_HANDLE_HASH_MAPPING_SLOT = 11; + uint256 public constant PRIMARY_CHARACTER_BY_ADDRESS_MAPPING_SLOT = 12; + uint256 public constant ATTACHED_LINK_LISTS_MAPPING_SLOT = 13; + uint256 public constant NOTES_MAPPING_SLOT = 14; + uint256 public constant LINK_MODULE_4_LINKLIST_MAPPING_SLOT = 15; + uint256 public constant LINK_MODULE_4_ERC721_MAPPING_SLOT = 16; + uint256 public constant LINK_MODULE_4_ADDRESS_MAPPING_SLOT = 17; + uint256 public constant CHARACTER_COUNTER_SLOG = 18; + uint256 public constant LINKLIST_SLOT = 19; + uint256 public constant MINT_NFT_IMPL_SLOT = 20; + uint256 public constant PERIPHERY_SLOT = 21; + // Slot 22 is deprecated + // Slot 23 is deprecated + uint256 public constant OPERATORS_BY_CHARACTER_MAPPING_SLOT = 24; + uint256 public constant OPERATORS_PERMISSION_BIT_MAP_MAPPING_SLOT = 25; + uint256 public constant OPERATOR_FOR_NOTE_MAPPING_SLOT = 26; + uint256 public constant NEWBIE_VILLA_SLOT = 27; + uint256 public constant SIG_NONCES_MAPPING_SLOT = 28; + + function setOperatorsPermissionBitMap( + uint256 characterId, + address operator, + uint256 permissionBitMap + ) internal { + assembly { + mstore(0, characterId) + mstore(32, OPERATORS_PERMISSION_BIT_MAP_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, operator) + sstore(keccak256(0, 64), permissionBitMap) + } + } + + function setAttachedLinklistId( + uint256 characterId, + bytes32 linkType, + uint256 linklistId + ) internal { + assembly { + mstore(0, characterId) + mstore(32, ATTACHED_LINK_LISTS_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, linkType) + sstore(keccak256(0, 64), linklistId) + } + } + + function deleteAttachedLinklistId(uint256 characterId, bytes32 linkType) internal { + assembly { + mstore(0, characterId) + mstore(32, ATTACHED_LINK_LISTS_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, linkType) + sstore(keccak256(0, 64), 0) + } + } + + function getAttachedLinklistId( + uint256 characterId, + bytes32 linkType + ) internal view returns (uint256 _linklistId) { + assembly { + mstore(0, characterId) + mstore(32, ATTACHED_LINK_LISTS_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, linkType) + _linklistId := sload(keccak256(0, 64)) + } + } + + function nonces() internal pure returns (mapping(address => uint256) storage _nonces) { + assembly { + _nonces.slot := SIG_NONCES_MAPPING_SLOT + } + } + + function getCharacter( + uint256 characterId + ) internal pure returns (DataTypes.Character storage _character) { + assembly { + mstore(0, characterId) + mstore(32, CHARACTERS_MAPPING_SLOT) + _character.slot := keccak256(0, 64) + } + } + + function getNote( + uint256 characterId, + uint256 noteId + ) internal pure returns (DataTypes.Note storage _note) { + assembly { + mstore(0, characterId) + mstore(32, NOTES_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, noteId) + _note.slot := keccak256(0, 64) + } + } + + function characterIdByHandleHash() + internal + pure + returns (mapping(bytes32 => uint256) storage _characterIdByHandleHash) + { + assembly { + _characterIdByHandleHash.slot := CHARACTER_ID_BY_HANDLE_HASH_MAPPING_SLOT + } + } + + function operatorsByCharacter() + internal + pure + returns (mapping(uint256 => EnumerableSet.AddressSet) storage _operatorsByCharacter) + { + assembly { + _operatorsByCharacter.slot := OPERATORS_BY_CHARACTER_MAPPING_SLOT + } + } + + function getOperators4Note( + uint256 characterId, + uint256 noteId + ) internal pure returns (DataTypes.Operators4Note storage _operators4Note) { + assembly { + mstore(0, characterId) + mstore(32, OPERATOR_FOR_NOTE_MAPPING_SLOT) + mstore(32, keccak256(0, 64)) + mstore(0, noteId) + _operators4Note.slot := keccak256(0, 64) + } + } +} diff --git a/contracts/libraries/ValidationLib.sol b/contracts/libraries/ValidationLib.sol new file mode 100644 index 000000000..b14511576 --- /dev/null +++ b/contracts/libraries/ValidationLib.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.18; + +import {StorageLib} from "./StorageLib.sol"; +import {Constants} from "./Constants.sol"; +import { + ErrHandleExists, + ErrNoteIsDeleted, + ErrNoteNotExists, + ErrNoteLocked, + ErrHandleLengthInvalid, + ErrHandleContainsInvalidCharacters +} from "./Error.sol"; + +// solhint-disable-next-line no-empty-blocks +library ValidationLib { + function validateNoteExists(uint256 characterId, uint256 noteId) internal view { + if (StorageLib.getNote(characterId, noteId).deleted) revert ErrNoteIsDeleted(); + if (noteId > StorageLib.getCharacter(characterId).noteCount) revert ErrNoteNotExists(); + } + + function validateNoteNotLocked(uint256 characterId, uint256 noteId) internal view { + if (StorageLib.getNote(characterId, noteId).locked) revert ErrNoteLocked(); + } + + function validateHandleNotExists(bytes32 handleHash) internal view { + if (StorageLib.characterIdByHandleHash()[handleHash] != 0) revert ErrHandleExists(); + } + + function validateHandle(string memory handle) internal pure { + bytes memory byteHandle = bytes(handle); + uint256 len = byteHandle.length; + if (len > Constants.MAX_HANDLE_LENGTH || len < Constants.MIN_HANDLE_LENGTH) + revert ErrHandleLengthInvalid(); + + for (uint256 i = 0; i < len; ) { + validateChar(byteHandle[i]); + + unchecked { + ++i; + } + } + } + + function validateChar(bytes1 c) internal pure { + // char range: [0,9][a,z][-][_] + if ((c < "0" || c > "z" || (c > "9" && c < "a")) && c != "-" && c != "_") + revert ErrHandleContainsInvalidCharacters(); + } +} diff --git a/contracts/misc/TipsWithConfig.sol b/contracts/misc/TipsWithConfig.sol index 5c969a647..11fcb10ef 100644 --- a/contracts/misc/TipsWithConfig.sol +++ b/contracts/misc/TipsWithConfig.sol @@ -125,6 +125,7 @@ contract TipsWithConfig is ITipsWithConfig, Initializable, ReentrancyGuard { } /// @inheritdoc ITipsWithConfig + // solhint-disable-next-line function-max-lines function setTipsConfig4Character( uint256 fromCharacterId, uint256 toCharacterId, @@ -205,9 +206,11 @@ contract TipsWithConfig is ITipsWithConfig, Initializable, ReentrancyGuard { } /// @inheritdoc ITipsWithConfig - function collectTips4Character(uint256 tipConfigId) external override nonReentrant { + function collectTips4Character( + uint256 tipConfigId + ) external override nonReentrant returns (uint256 collectedAmount) { // collect tips - _collectTips4Character(tipConfigId); + collectedAmount = _collectTips4Character(tipConfigId); } /// @inheritdoc ITipsWithConfig @@ -247,17 +250,17 @@ contract TipsWithConfig is ITipsWithConfig, Initializable, ReentrancyGuard { return _web3Entry; } - function _collectTips4Character(uint256 tipConfigId) internal { + function _collectTips4Character(uint256 tipConfigId) internal returns (uint256) { TipsConfig storage config = _tipsConfigs[tipConfigId]; // not started if (config.startTime > block.timestamp) { - return; + return 0; } // already ended if (config.currentRound >= config.totalRound) { - return; + return 0; } (uint256 currentRound, uint256 availableAmount) = _getAvailableRoundAndAmount(config); @@ -293,6 +296,8 @@ contract TipsWithConfig is ITipsWithConfig, Initializable, ReentrancyGuard { currentRound ); } + + return availableAmount; } function _getTipsConfigId( diff --git a/contracts/misc/TipsWithFee.sol b/contracts/misc/TipsWithFee.sol index 6be8a376d..8f3455de3 100644 --- a/contracts/misc/TipsWithFee.sol +++ b/contracts/misc/TipsWithFee.sol @@ -313,7 +313,7 @@ contract TipsWithFee is ITipsWithFee, Initializable, IERC777Recipient { amount - feeAmount, userData ); - // solhint-disable-next-line check-send-result + // solhint-disable-next-line check-send-result,multiple-sends IERC777(token).send(feeReceiver, feeAmount, userData); // emit event diff --git a/contracts/mocks/ERC1271WalletMock.sol b/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 000000000..3f14e8731 --- /dev/null +++ b/contracts/mocks/ERC1271WalletMock.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// solhint-disable one-contract-per-file +pragma solidity ^0.8.0; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; + +contract ERC1271WalletMock is Ownable, IERC1271, IERC721Receiver { + constructor(address originalOwner) { + transferOwnership(originalOwner); + } + + function isValidSignature( + bytes32 hash, + bytes memory signature + ) external view override returns (bytes4 magicValue) { + return + ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); + } + + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external pure override returns (bytes4) { + return this.onERC721Received.selector; + } +} + +contract ERC1271MaliciousMock is IERC1271, IERC721Receiver { + function isValidSignature(bytes32, bytes memory) external pure override returns (bytes4) { + return 0xffffffff; + } + + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external pure override returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/contracts/mocks/NFT.sol b/contracts/mocks/NFT.sol index 30c91994b..6cf2666fd 100644 --- a/contracts/mocks/NFT.sol +++ b/contracts/mocks/NFT.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// solhint-disable comprehensive-interface +// solhint-disable comprehensive-interface,one-contract-per-file pragma solidity 0.8.18; import {NFTBase} from "../base/NFTBase.sol"; diff --git a/contracts/modules/ModuleBase.sol b/contracts/modules/ModuleBase.sol index 1d5354090..83b38547f 100644 --- a/contracts/modules/ModuleBase.sol +++ b/contracts/modules/ModuleBase.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.18; import {ErrCallerNotWeb3Entry, ErrInvalidWeb3Entry} from "../libraries/Error.sol"; abstract contract ModuleBase { + // solhint-disable-next-line immutable-vars-naming address public immutable web3Entry; modifier onlyWeb3Entry() { diff --git a/contracts/storage/Web3EntryStorage.sol b/contracts/storage/Web3EntryStorage.sol index d9817b6f3..4604cb46d 100644 --- a/contracts/storage/Web3EntryStorage.sol +++ b/contracts/storage/Web3EntryStorage.sol @@ -5,17 +5,6 @@ pragma solidity 0.8.18; import {DataTypes} from "../libraries/DataTypes.sol"; contract Web3EntryStorage { - // solhint-disable-next-line private-vars-leading-underscore, var-name-mixedcase - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ); - // solhint-disable-next-line private-vars-leading-underscore, var-name-mixedcase - bytes32 internal constant GRANT_OPERATOR_PERMISSIONS_WITH_SIG_TYPEHASH = - keccak256( // solhint-disable-next-line max-line-length - "grantOperatorPermissions(uint256 characterId,address operator,uint256 permissionBitMap,uint256 nonce,uint256 deadline)" - ); - // characterId => Character mapping(uint256 => DataTypes.Character) internal _characterById; // handleHash => characterId diff --git a/contracts/upgradeability/ProxyAdmin.sol b/contracts/upgradeability/ProxyAdmin.sol deleted file mode 100644 index b34f342a7..000000000 --- a/contracts/upgradeability/ProxyAdmin.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol) - -pragma solidity 0.8.18; - -import "./TransparentUpgradeableProxy.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an - * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. - */ -contract ProxyAdmin is Ownable { - /** - * @dev Returns the current implementation of `proxy`. - * - * Requirements: - * - * - This contract must be the admin of `proxy`. - */ - function getProxyImplementation( - TransparentUpgradeableProxy proxy - ) public view virtual returns (address) { - // We need to manually run the static call since the getter cannot be flagged as view - // bytes4(keccak256("implementation()")) == 0x5c60da1b - (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); - require(success); - return abi.decode(returndata, (address)); - } - - /** - * @dev Returns the current admin of `proxy`. - * - * Requirements: - * - * - This contract must be the admin of `proxy`. - */ - function getProxyAdmin( - TransparentUpgradeableProxy proxy - ) public view virtual returns (address) { - // We need to manually run the static call since the getter cannot be flagged as view - // bytes4(keccak256("admin()")) == 0xf851a440 - (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); - require(success); - return abi.decode(returndata, (address)); - } - - /** - * @dev Changes the admin of `proxy` to `newAdmin`. - * - * Requirements: - * - * - This contract must be the current admin of `proxy`. - */ - function changeProxyAdmin( - TransparentUpgradeableProxy proxy, - address newAdmin - ) public virtual onlyOwner { - proxy.changeAdmin(newAdmin); - } - - /** - * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. - * - * Requirements: - * - * - This contract must be the admin of `proxy`. - */ - function upgrade( - TransparentUpgradeableProxy proxy, - address implementation - ) public virtual onlyOwner { - proxy.upgradeTo(implementation); - } - - /** - * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See - * {TransparentUpgradeableProxy-upgradeToAndCall}. - * - * Requirements: - * - * - This contract must be the admin of `proxy`. - */ - function upgradeAndCall( - TransparentUpgradeableProxy proxy, - address implementation, - bytes memory data - ) public payable virtual onlyOwner { - proxy.upgradeToAndCall{value: msg.value}(implementation, data); - } -} diff --git a/scripts/UpgradeLinklist.sol b/scripts/UpgradeLinklist.sol deleted file mode 100644 index 3a6cba580..000000000 --- a/scripts/UpgradeLinklist.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.18; - -import "@std/Test.sol"; -import "@std/Script.sol"; -import "../Linklist.sol"; -import "../upgradeability/TransparentUpgradeableProxy.sol"; - -contract UpgradeLinklist is Script { - address payable public linklistProxy = payable(0xFc8C75bD5c26F50798758f387B698f207a016b6A); - - /* solhint-disable comprehensive-interface */ - function run() external { - vm.startBroadcast(); - - Linklist linklist = new Linklist(); - TransparentUpgradeableProxy proxy = TransparentUpgradeableProxy(linklistProxy); - proxy.upgradeTo(address(linklist)); - - vm.stopBroadcast(); - } -} diff --git a/scripts/UpgradePeriphery.sol b/scripts/UpgradePeriphery.sol deleted file mode 100644 index 9866af675..000000000 --- a/scripts/UpgradePeriphery.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.18; - -import "@std/Test.sol"; -import "@std/Script.sol"; -import "src/Web3Entry.sol"; -import "src/misc/Periphery.sol"; -import "src/upgradeability/TransparentUpgradeableProxy.sol"; - -contract UpgradePeriphery is Script { - address payable public peripheryProxy = payable(0x96e96b7AF62D628cE7eb2016D2c1D2786614eA73); - - /* solhint-disable comprehensive-interface */ - function run() external { - vm.startBroadcast(); - - Periphery periphery = new Periphery(); - TransparentUpgradeableProxy proxy = TransparentUpgradeableProxy(peripheryProxy); - proxy.upgradeTo(address(periphery)); - - vm.stopBroadcast(); - } -} diff --git a/scripts/UpgradeWeb3Entry.sol b/scripts/UpgradeWeb3Entry.sol deleted file mode 100644 index 15da67190..000000000 --- a/scripts/UpgradeWeb3Entry.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.18; - -import "@std/Test.sol"; -import "@std/Script.sol"; -import "../Web3Entry.sol"; -import "../upgradeability/TransparentUpgradeableProxy.sol"; - -contract UpgradeWeb3Entry is Script { - address payable public web3EntryProxy = payable(0xa6f969045641Cf486a747A2688F3a5A6d43cd0D8); - - /* solhint-disable comprehensive-interface */ - function run() external { - vm.startBroadcast(); - - Web3Entry web3Entry = new Web3Entry(); - TransparentUpgradeableProxy proxy = TransparentUpgradeableProxy(web3EntryProxy); - proxy.upgradeTo(address(web3Entry)); - - vm.stopBroadcast(); - } -} diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 63ca6ae9a..bf1aeeb37 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -29,28 +29,32 @@ async function main() { const Periphery = await ethers.getContractFactory("Periphery"); const periphery = await Periphery.deploy(); - const LinkModuleLogic = await ethers.getContractFactory("LinkModuleLogic"); - const linkModuleLogic = await LinkModuleLogic.deploy(); + const CharacterLib = await ethers.getContractFactory("CharacterLib"); + const characterLib = await CharacterLib.deploy(); - const CharacterLogic = await ethers.getContractFactory("CharacterLogic"); - const characterLogic = await CharacterLogic.deploy(); + const OperatorLib = await ethers.getContractFactory("OperatorLib"); + const operatorLib = await OperatorLib.deploy(); - const OperatorLogic = await ethers.getContractFactory("OperatorLogic"); - const operatorLogic = await OperatorLogic.deploy(); + const PostLib = await ethers.getContractFactory("PostLib"); + const postLib = await PostLib.deploy(); - const PostLogic = await ethers.getContractFactory("PostLogic"); - const postLogic = await PostLogic.deploy(); + const LinkLib = await ethers.getContractFactory("LinkLib"); + const linkLib = await LinkLib.deploy(); - const LinkLogic = await ethers.getContractFactory("LinkLogic"); - const linkLogic = await LinkLogic.deploy(); + const LinklistLib = await ethers.getContractFactory("LinklistLib"); + const linklistLib = await LinklistLib.deploy(); + + const MetaTxLib = await ethers.getContractFactory("MetaTxLib"); + const metaTxLib = await MetaTxLib.deploy(); const Web3Entry = await ethers.getContractFactory("Web3Entry", { libraries: { - LinkModuleLogic: linkModuleLogic.address, - CharacterLogic: characterLogic.address, - OperatorLogic: operatorLogic.address, - PostLogic: postLogic.address, - LinkLogic: linkLogic.address, + CharacterLib: characterLib.address, + OperatorLib: operatorLib.address, + PostLib: postLib.address, + LinkLib: linkLib.address, + LinklistLib: linklistLib.address, + MetaTxLib: metaTxLib.address, }, }); const web3Entry = await Web3Entry.deploy(); @@ -89,10 +93,11 @@ async function main() { .connect(addr1) .initialize(proxyWeb3Entry.address, proxyLinklist.address); - console.log("LinkModuleLogic deployed to:", linkModuleLogic.address); - console.log("CharacterLogic deployed to:", characterLogic.address); - console.log("PostLogic deployed to:", postLogic.address); - console.log("LinkLogic deployed to:", linkLogic.address); + console.log("CharacterLib.sol deployed to:", characterLib.address); + console.log("PostLib.sol deployed to:", postLib.address); + console.log("LinkLib.sol deployed to:", linkLib.address); + console.log("LinklistLib.sol deployed to:", linklistLib.address); + console.log("MetaTxLib.sol deployed to:", metaTxLib.address); console.log("Web3Entry deployed to:", web3Entry.address); console.log("periphery deployed to:", periphery.address); console.log("Linklist deployed to:", linkList.address); diff --git a/scripts/deployWeb3Entry.ts b/scripts/deployWeb3Entry.ts index cbe0aae18..83c96cd06 100644 --- a/scripts/deployWeb3Entry.ts +++ b/scripts/deployWeb3Entry.ts @@ -21,28 +21,32 @@ async function main() { // We get the contract to deploy - const CharacterLogic = await ethers.getContractFactory("CharacterLogic"); - const characterLogic = await CharacterLogic.deploy(); + const CharacterLib = await ethers.getContractFactory("CharacterLib"); + const characterLib = await CharacterLib.deploy(); - const PostLogic = await ethers.getContractFactory("PostLogic"); - const postLogic = await PostLogic.deploy(); + const PostLib = await ethers.getContractFactory("PostLib"); + const postLib = await PostLib.deploy(); - const LinkLogic = await ethers.getContractFactory("LinkLogic"); - const linkLogic = await LinkLogic.deploy(); + const LinkLib = await ethers.getContractFactory("LinkLib"); + const linkLib = await LinkLib.deploy(); - const LinklistLogic = await ethers.getContractFactory("LinklistLogic"); - const linklistLogic = await LinklistLogic.deploy(); + const LinklistLib = await ethers.getContractFactory("LinklistLib"); + const linklistLib = await LinklistLib.deploy(); - const OperatorLogic = await ethers.getContractFactory("OperatorLogic"); - const operatorLogic = await OperatorLogic.deploy(); + const OperatorLib = await ethers.getContractFactory("OperatorLib"); + const operatorLib = await OperatorLib.deploy(); + + const MetaTxLib = await ethers.getContractFactory("MetaTxLib"); + const metaTxLib = await MetaTxLib.deploy(); const Web3Entry = await ethers.getContractFactory("Web3Entry", { libraries: { - CharacterLogic: characterLogic.address, - PostLogic: postLogic.address, - LinkLogic: linkLogic.address, - LinklistLogic: linklistLogic.address, - OperatorLogic: operatorLogic.address, + CharacterLib: characterLib.address, + PostLib: postLib.address, + LinkLib: linkLib.address, + LinklistLib: linklistLib.address, + OperatorLib: operatorLib.address, + MetaTxLib: metaTxLib.address, }, }); const web3Entry = await Web3Entry.deploy(); @@ -56,11 +60,10 @@ async function main() { newbieVilla, ); - console.log("CharacterLogic deployed to:", characterLogic.address); - console.log("PostLogic deployed to:", postLogic.address); - console.log("LinkLogic deployed to:", linkLogic.address); - console.log("LinklistLogic deployed to:", linklistLogic.address); - console.log("OperatorLogic deployed to:", operatorLogic.address); + console.log("CharacterLib.sol deployed to:", characterLib.address); + console.log("PostLib.sol deployed to:", postLib.address); + console.log("LinkLib.sol deployed to:", linkLib.address); + console.log("OperatorLib.sol deployed to:", operatorLib.address); console.log("Web3Entry deployed to:", web3Entry.address); } diff --git a/scripts/upgradeLinklist.ts b/scripts/upgradeLinklist.ts deleted file mode 100644 index 96c0a4897..000000000 --- a/scripts/upgradeLinklist.ts +++ /dev/null @@ -1,34 +0,0 @@ -// We require the Hardhat Runtime Environment explicitly here. This is optional -// but useful for running the script in a standalone fashion through `node