diff --git a/packages/contracts/CHANGELOG.md b/packages/contracts/CHANGELOG.md index fea44c132..c8bad728e 100644 --- a/packages/contracts/CHANGELOG.md +++ b/packages/contracts/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## UPCOMING + +### Added + +- Added `allowFailureMap` to `IDAO.Executed` event. + ## v1.2.0 ### Added diff --git a/packages/contracts/src/core/dao/DAO.sol b/packages/contracts/src/core/dao/DAO.sol index d5f9c1b5c..a22784de6 100644 --- a/packages/contracts/src/core/dao/DAO.sol +++ b/packages/contracts/src/core/dao/DAO.sol @@ -227,6 +227,7 @@ contract DAO is actor: msg.sender, callId: _callId, actions: _actions, + allowFailureMap: _allowFailureMap, failureMap: failureMap, execResults: execResults }); diff --git a/packages/contracts/src/core/dao/IDAO.sol b/packages/contracts/src/core/dao/IDAO.sol index ecad406cc..099d7a1e8 100644 --- a/packages/contracts/src/core/dao/IDAO.sol +++ b/packages/contracts/src/core/dao/IDAO.sol @@ -53,6 +53,7 @@ interface IDAO { /// @param actor The address of the caller. /// @param callId The ID of the call. /// @param actions The array of actions executed. + /// @param allowFailureMap The allow failure map encoding which actions are allowed to fail. /// @param failureMap The failure map encoding which actions have failed. /// @param execResults The array with the results of the executed actions. /// @dev The value of `callId` is defined by the component/contract calling the execute function. A `Plugin` implementation can use it, for example, as a nonce. @@ -60,6 +61,7 @@ interface IDAO { address indexed actor, bytes32 callId, Action[] actions, + uint256 allowFailureMap, uint256 failureMap, bytes[] execResults ); diff --git a/packages/contracts/src/test/dao/DAOMock.sol b/packages/contracts/src/test/dao/DAOMock.sol index 7f360960f..260a9135c 100644 --- a/packages/contracts/src/test/dao/DAOMock.sol +++ b/packages/contracts/src/test/dao/DAOMock.sol @@ -38,7 +38,7 @@ contract DAOMock is IDAO, PermissionManager { uint256 allowFailureMap ) external override returns (bytes[] memory execResults, uint256 failureMap) { (allowFailureMap); - emit Executed(msg.sender, callId, _actions, failureMap, execResults); + emit Executed(msg.sender, callId, _actions, allowFailureMap, failureMap, execResults); } function deposit( diff --git a/packages/contracts/test/core/dao/dao.ts b/packages/contracts/test/core/dao/dao.ts index 85e45e1da..bf3c87485 100644 --- a/packages/contracts/test/core/dao/dao.ts +++ b/packages/contracts/test/core/dao/dao.ts @@ -333,6 +333,7 @@ describe('DAO', function () { expect(event.args.actor).to.equal(ownerAddress); expect(event.args.callId).to.equal(ZERO_BYTES32); + expect(event.args.allowFailureMap).to.equal(allowFailureMap); // construct the failureMap which only has those // bits set at indexes where actions failed @@ -340,7 +341,7 @@ describe('DAO', function () { for (let i = 0; i < 3; i++) { failureMap = flipBit(i, failureMap); } - // Check that dao crrectly generated failureMap + // Check that dao correctly generated failureMap expect(event.args.failureMap).to.equal(failureMap); // Check that execResult emitted correctly stores action results. @@ -372,6 +373,7 @@ describe('DAO', function () { expect(event.args.actions[0].value).to.equal(data.succeedAction.value); expect(event.args.actions[0].data).to.equal(data.succeedAction.data); expect(event.args.execResults[0]).to.equal(data.successActionResult); + expect(event.args.allowFailureMap).to.equal(0); }); it('reverts if failure is allowed but not enough gas is provided', async () => { @@ -392,11 +394,11 @@ describe('DAO', function () { [gasConsumingAction], allowFailureMap ); // exact gas required: 495453 - // Providing less gas causes the `to.call` of the `gasConsumingAction` to fail, but is still enough for the overall `dao.execute` call to finish successfully. + // Providing less gas causes the `to.call` of the `gasConsumingAction` to fail, but is still enough for the overall `dao.execute` call to finish successfully. await expect( dao.execute(ZERO_BYTES32, [gasConsumingAction], allowFailureMap, { - gasLimit: expectedGas.sub(500), + gasLimit: expectedGas.sub(800), }) ).to.be.revertedWithCustomError(dao, 'InsufficientGas'); diff --git a/packages/subgraph/CHANGELOG.md b/packages/subgraph/CHANGELOG.md index a2b36d248..f07bc0582 100644 --- a/packages/subgraph/CHANGELOG.md +++ b/packages/subgraph/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [UPCOMING] +### Changed + +- Supports now multiple `DAORegistries`, `PluginRepoRegistries` and `PluginSetupProcessors` as datasources. +- Splits `DAO` into multiple versions. +- Fixes typing issues in tests and subgraph manifest. + ## [1.1.0] ### Added diff --git a/packages/subgraph/abis/DAO_v1_0_0.json b/packages/subgraph/abis/DAO_v1_0_0.json new file mode 100644 index 000000000..050f85330 --- /dev/null +++ b/packages/subgraph/abis/DAO_v1_0_0.json @@ -0,0 +1,1092 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "DAO", + "sourceName": "src/core/dao/DAO.sol", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "ActionFailed", + "type": "error" + }, + { + "inputs": [], + "name": "AnyAddressDisallowedForWhoAndWhere", + "type": "error" + }, + { + "inputs": [], + "name": "ConditionNotPresentForAnyAddress", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientGas", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "NativeTokenDepositAmountMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "where", + "type": "address" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "currentCondition", + "type": "address" + }, + { + "internalType": "address", + "name": "newCondition", + "type": "address" + } + ], + "name": "PermissionAlreadyGrantedForDifferentCondition", + "type": "error" + }, + { + "inputs": [], + "name": "PermissionsForAnyAddressDisallowed", + "type": "error" + }, + { + "inputs": [], + "name": "TooManyActions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "where", + "type": "address" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "callbackSelector", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "magicNumber", + "type": "bytes4" + } + ], + "name": "UnkownCallback", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAmount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "sig", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "CallbackReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "_reference", + "type": "string" + } + ], + "name": "Deposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "callId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct IDAO.Action[]", + "name": "actions", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "failureMap", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "execResults", + "type": "bytes[]" + } + ], + "name": "Executed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "here", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "where", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IPermissionCondition", + "name": "condition", + "type": "address" + } + ], + "name": "Granted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "MetadataSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "NativeTokenDeposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "daoURI", + "type": "string" + } + ], + "name": "NewURI", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "here", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "where", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "who", + "type": "address" + } + ], + "name": "Revoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "signatureValidator", + "type": "address" + } + ], + "name": "SignatureValidatorSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "callbackSelector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "magicNumber", + "type": "bytes4" + } + ], + "name": "StandardCallbackRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "forwarder", + "type": "address" + } + ], + "name": "TrustedForwarderSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "fallback" + }, + { + "inputs": [], + "name": "EXECUTE_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REGISTER_STANDARD_CALLBACK_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ROOT_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SET_METADATA_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SET_SIGNATURE_VALIDATOR_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SET_TRUSTED_FORWARDER_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_DAO_PERMISSION_ID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum PermissionLib.Operation", + "name": "operation", + "type": "uint8" + }, + { + "internalType": "address", + "name": "where", + "type": "address" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "address", + "name": "condition", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + } + ], + "internalType": "struct PermissionLib.MultiTargetPermission[]", + "name": "_items", + "type": "tuple[]" + } + ], + "name": "applyMultiTargetPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "components": [ + { + "internalType": "enum PermissionLib.Operation", + "name": "operation", + "type": "uint8" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "permissionId", + "type": "bytes32" + } + ], + "internalType": "struct PermissionLib.SingleTargetPermission[]", + "name": "items", + "type": "tuple[]" + } + ], + "name": "applySingleTargetPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "daoURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_reference", + "type": "string" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_callId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IDAO.Action[]", + "name": "_actions", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "_allowFailureMap", + "type": "uint256" + } + ], + "name": "execute", + "outputs": [ + { + "internalType": "bytes[]", + "name": "execResults", + "type": "bytes[]" + }, + { + "internalType": "uint256", + "name": "failureMap", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getTrustedForwarder", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "internalType": "address", + "name": "_who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_permissionId", + "type": "bytes32" + } + ], + "name": "grant", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "internalType": "address", + "name": "_who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_permissionId", + "type": "bytes32" + }, + { + "internalType": "contract IPermissionCondition", + "name": "_condition", + "type": "address" + } + ], + "name": "grantWithCondition", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "internalType": "address", + "name": "_who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_permissionId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "hasPermission", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + }, + { + "internalType": "address", + "name": "_initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "_trustedForwarder", + "type": "address" + }, + { + "internalType": "string", + "name": "daoURI_", + "type": "string" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "internalType": "address", + "name": "_who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_permissionId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "isGranted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "_callbackSelector", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "_magicNumber", + "type": "bytes4" + } + ], + "name": "registerStandardCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_where", + "type": "address" + }, + { + "internalType": "address", + "name": "_who", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_permissionId", + "type": "bytes32" + } + ], + "name": "revoke", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "newDaoURI", + "type": "string" + } + ], + "name": "setDaoURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "setMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_signatureValidator", + "type": "address" + } + ], + "name": "setSignatureValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newTrustedForwarder", + "type": "address" + } + ], + "name": "setTrustedForwarder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "signatureValidator", + "outputs": [ + { + "internalType": "contract IERC1271", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e8565b600054610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e6576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6080516135ad6200012060003960008181610a6c01528181610b0201528181610c9701528181610d2d0152610e2801526135ad6000f3fe6080604052600436106101d15760003560e01c8063829331a1116100f7578063d96054c411610095578063e978afe511610064578063e978afe5146106b2578063eafb8b06146106d2578063ee57e36f146106f2578063fdef91061461071257610210565b8063d96054c41461060a578063da7422281461062a578063e2e355631461064a578063e306bee71461067e57610210565b8063c71bf324116100d1578063c71bf3241461057d578063c9dbc2a4146105ab578063ce1b815f146105cb578063d68bad2c146105ea57610210565b8063829331a114610516578063bfe07da61461054a578063c4a501451461055d57610210565b80632675fdd01161016f5780633e2ab0d91161013e5780633e2ab0d9146104ac5780634f1ef286146104cc57806352d1902d146104df5780637034731b146104f457610210565b80632675fdd0146103ff57806326875b1f1461041f5780633659cfe614610453578063388da9341461047357610210565b80631080f99b116101ab5780631080f99b146103505780631626ba7e1461037257806322844d04146103ab57806324b4d73f146103cb57610210565b806301ffc9a7146102a55780630729d054146102da57806309e56b141461031c57610210565b3661021057604080513381523460208201527f62c2c8e34665db7c56b2cabd7f5fb9702ccd352ffa8150147e450797e9f8e8f3910160405180910390a1005b34801561021c57600080fd5b50600036606060006102706000356001600160e01b03191685858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061073292505050565b604080516001600160e01b03198316602082015291925001604051602081830303815290604052915050915050805190602001f35b3480156102b157600080fd5b506102c56102c036600461293e565b610809565b60405190151581526020015b60405180910390f35b3480156102e657600080fd5b5061030e7fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d81565b6040519081526020016102d1565b34801561032857600080fd5b5061030e7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3381565b34801561035c57600080fd5b5061037061036b3660046129a4565b61085e565b005b34801561037e57600080fd5b5061039261038d366004612a89565b610897565b6040516001600160e01b031990911681526020016102d1565b3480156103b757600080fd5b506103706103c6366004612ae5565b610947565b3480156103d757600080fd5b5061030e7f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc81565b34801561040b57600080fd5b506102c561041a366004612b6d565b610a17565b34801561042b57600080fd5b5061030e7ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc81565b34801561045f57600080fd5b5061037061046e366004612bd9565b610a62565b34801561047f57600080fd5b5061012d54610494906001600160a01b031681565b6040516001600160a01b0390911681526020016102d1565b3480156104b857600080fd5b506103706104c7366004612bd9565b610bff565b6103706104da366004612bf6565b610c8d565b3480156104eb57600080fd5b5061030e610e1b565b34801561050057600080fd5b50610509610ee0565b6040516102d19190612c80565b34801561052257600080fd5b5061030e7f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c81565b610370610558366004612c93565b610f73565b34801561056957600080fd5b50610370610578366004612cef565b6110ad565b34801561058957600080fd5b5061059d610598366004612d3a565b611160565b6040516102d1929190612e14565b3480156105b757600080fd5b506103706105c6366004612e36565b611439565b3480156105d757600080fd5b5061012e546001600160a01b0316610494565b3480156105f657600080fd5b50610370610605366004612e89565b61146f565b34801561061657600080fd5b50610370610625366004612e89565b6114aa565b34801561063657600080fd5b50610370610645366004612bd9565b6114df565b34801561065657600080fd5b5061030e7f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e77808837281565b34801561068a57600080fd5b5061030e7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b81565b3480156106be57600080fd5b506103706106cd366004612eca565b611512565b3480156106de57600080fd5b506103706106ed366004612f3f565b611619565b3480156106fe57600080fd5b5061037061070d3660046129a4565b6117e0565b34801561071e57600080fd5b506102c561072d366004612b6d565b611814565b6001600160e01b0319808316600090815260fb6020526040812054909160e09190911b9081166107a7576040517f54bdcc3e0000000000000000000000000000000000000000000000000000000081526001600160e01b03198086166004830152821660248201526044015b60405180910390fd5b837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f4792cb6e46e49876374bea490ba23274bacea6b84c216a64f47abab54027589b33856040516107f8929190612fd8565b60405180910390a290505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806108035750506001600160e01b03191660009081526033602052604090205460ff1690565b7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b61088881611822565b61089283836118aa565b505050565b61012d546000906001600160a01b03166108b357506000610803565b61012d546040517f1626ba7e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690631626ba7e906108ff9086908690600401612ffa565b602060405180830381865afa15801561091c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109409190613013565b9392505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361097181611822565b60005b82811015610a1057600084848381811061099057610990613030565b9050606002018036038101906109a6919061305a565b90506000815160028111156109bd576109bd6130c3565b036109da576109d586826020015183604001516118ea565b610a07565b6001815160028111156109ef576109ef6130c3565b03610a0757610a0786826020015183604001516118f7565b50600101610974565b5050505050565b6000610a25858585856119fe565b80610a3e5750610a3e856001600160a01b0385856119fe565b80610a575750610a576001600160a01b038585856119fe565b90505b949350505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610b005760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c0000000000000000000000000000000000000000606482015260840161079e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614610bd75760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f78790000000000000000000000000000000000000000606482015260840161079e565b610be081611b72565b60408051600080825260208201909252610bfc91839190611b9c565b50565b7f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e778088372610c2981611822565b61012d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527f3b25c5d3870ec0eac28822b177f18c9130233ade5b7f857c6a224a507c37fc4e906020015b60405180910390a15050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d2b5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c0000000000000000000000000000000000000000606482015260840161079e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610d867f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614610e025760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f78790000000000000000000000000000000000000000606482015260840161079e565b610e0b82611b72565b610e1782826001611b9c565b5050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ebb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161079e565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b606061012f8054610ef0906130d9565b80601f0160208091040260200160405190810160405280929190818152602001828054610f1c906130d9565b8015610f695780601f10610f3e57610100808354040283529160200191610f69565b820191906000526020600020905b815481529060010190602001808311610f4c57829003601f168201915b5050505050905090565b82600003610fad576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841661100257823414610ffd576040517f1abd56100000000000000000000000000000000000000000000000000000000081526004810184905234602482015260440161079e565b611058565b3415611043576040517f1abd56100000000000000000000000000000000000000000000000000000000081526000600482015234602482015260440161079e565b6110586001600160a01b038516333086611d3c565b836001600160a01b0316336001600160a01b03167f2bc500cf071be2d1c1458ed6ff484cd4db4345ada8943dee7ff29e7af3558f7685858560405161109f9392919061313e565b60405180910390a350505050565b7ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc6110d781611822565b6110e084611dc4565b6001600160e01b03198316600090815260fb60205260409020805463ffffffff191660e084901c179055604080516001600160e01b0319808716825280861660208301528416918101919091527ffc72fd547553f7a663e0048e590afc9c47b56a4242e960f31cf4c62e23d308b99060600160405180910390a150505050565b606060007fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d61118e81611822565b6101008511156111ca576040517f11c763d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8467ffffffffffffffff8111156111e3576111e36129e6565b60405190808252806020026020018201604052801561121657816020015b60608152602001906001900390816112015790505b50925060008060005b878110156113e3575a92506000808a8a8481811061123f5761123f613030565b90506020028101906112519190613158565b61125f906020810190612bd9565b6001600160a01b03168b8b8581811061127a5761127a613030565b905060200281019061128c9190613158565b602001358c8c868181106112a2576112a2613030565b90506020028101906112b49190613158565b6112c2906040810190613178565b6040516112d09291906131bf565b60006040518083038185875af1925050503d806000811461130d576040519150601f19603f3d011682016040523d82523d6000602084013e611312565b606091505b50915091505a9350600160ff84161b89166113665781611361576040517fa6a7dbbd0000000000000000000000000000000000000000000000000000000081526004810184905260240161079e565b6113bb565b816113bb576113766040866131cf565b8410156113af576040517f1c26714c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160ff84161b871896505b808884815181106113ce576113ce613030565b6020908102919091010152505060010161121f565b50336001600160a01b03167fd0de18eab8dc7532aab0fc4eb308477031cabf9fd312ea3b3a5fe9aa45ac8ed78a8a8a888a6040516114259594939291906131f1565b60405180910390a250505094509492505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361146381611822565b610a1085858585611e43565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361149981611822565b6114a48484846118ea565b50505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada336114d481611822565b6114a48484846118f7565b7f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c61150981611822565b610e1782612101565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361153c81611822565b60005b828110156114a457600084848381811061155b5761155b613030565b905060a002018036038101906115719190613316565b9050600081516002811115611588576115886130c3565b036115a9576115a48160200151826040015183608001516118ea565b611610565b6001815160028111156115be576115be6130c3565b036115da576115a48160200151826040015183608001516118f7565b6002815160028111156115ef576115ef6130c3565b03611610576116108160200151826040015183608001518460600151611e43565b5060010161153f565b600054610100900460ff16158080156116395750600054600160ff909116105b806116535750303b158015611653575060005460ff166001145b6116c55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161079e565b6000805460ff1916600117905580156116e8576000805461ff0019166101001790555b6117117f9385547e00000000000000000000000000000000000000000000000000000000611dc4565b61173a7f1626ba7e00000000000000000000000000000000000000000000000000000000611dc4565b6117637f7034731b00000000000000000000000000000000000000000000000000000000611dc4565b61176b612163565b6117758787612270565b61177e84612101565b61178883836118aa565b611791856122a1565b80156117d7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b61180a81611822565b6108928383612270565b6000610a5785858585610a17565b6118653033836000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a1792505050565b610bfc576040517f1e09743f0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810182905260640161079e565b61012f6118b88284836133f3565b507fe9b617ecb5f63f6a9ccd8d4d5fa0d7b2ef9b17ce3f48e6b135808d6a40e677428282604051610c819291906134b3565b6108928383836002611e43565b604080517f5045524d495353494f4e000000000000000000000000000000000000000000006020808301919091526bffffffffffffffffffffffff19606086811b8216602a85015287901b16603e83015260528083018590528351808403909101815260729092019092528051910120600090600081815260c960205260409020549091506001600160a01b0316156114a457600081815260c96020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916905590516001600160a01b038681168252851691339185917f3ca48185ec3f6e47e24db18b13f1c65b1ce05da1659f9c1c4fe717dda5f67524910160405180910390a450505050565b60008060c96000611a838888886040517f5045524d495353494f4e0000000000000000000000000000000000000000000060208201526bffffffffffffffffffffffff19606084811b8216602a84015285901b16603e820152605281018290526000906072016040516020818303038152906040528051906020012090509392505050565b81526020810191909152604001600020546001600160a01b0316905080611aae576000915050610a5a565b6001196001600160a01b03821601611aca576001915050610a5a565b6040517f2675fdd00000000000000000000000000000000000000000000000000000000081526001600160a01b03821690632675fdd090611b159089908990899089906004016134c7565b602060405180830381865afa925050508015611b4e575060408051601f3d908101601f19168201909252611b4b91810190613503565b60015b15611b66578015611b6457600192505050610a5a565b505b50600095945050505050565b7f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc610e1781611822565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611bcf5761089283612327565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611c29575060408051601f3d908101601f19168201909252611c2691810190613525565b60015b611c9b5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f742055555053000000000000000000000000000000000000606482015260840161079e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114611d305760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c65555549440000000000000000000000000000000000000000000000606482015260840161079e565b506108928383836123f2565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526114a4908590612417565b6001600160e01b03198082169003611e1e5760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640161079e565b6001600160e01b0319166000908152603360205260409020805460ff19166001179055565b6001600160a01b03848116148015611e6357506001600160a01b03838116145b15611e9a576040517f85f1ba9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038481161480611eb957506001600160a01b03838116145b15611f73576000611ec9836124fc565b90507f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada33831480611ef65750805b15611f2d576040517f24159e5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001196001600160a01b03831601611f71576040517f92ab7d0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b604080517f5045524d495353494f4e000000000000000000000000000000000000000000006020808301919091526bffffffffffffffffffffffff19606087811b8216602a85015288901b16603e83015260528083018690528351808403909101815260729092019092528051910120600090600081815260c960205260409020549091506001600160a01b0316828161208c57600083815260c96020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038581169190911790915582518a8216815287821692810192909252881691339188917f0f579ad49235a8c1fd9041427e7067b1eb10926bbed380bf6fabc73e0e807644910160405180910390a46117d7565b806001600160a01b0316826001600160a01b0316146117d7576040517f0b98789e0000000000000000000000000000000000000000000000000000000081526001600160a01b03808916600483015280881660248301526044820187905280841660648301528216608482015260a40161079e565b61012e805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527fd91237492a9e30cd2faf361fc103998a382ff0ec2b1b07dc1cbebb76ae2f1ea29060200160405180910390a150565b61218c7f150b7a0200000000000000000000000000000000000000000000000000000000611dc4565b6121b57f4e2312e000000000000000000000000000000000000000000000000000000000611dc4565b60fb6020527f5a08f87af82de422c581ce019b2e54a9c17372e9cba575ae0470ba2482d63686805463ffffffff1990811663150b7a02179091557fe1cfe341950d56d8854f782066100d5ae1d5930cdb4949b973e554a343efc6c38054821663f23a6e611790557fbc197c81000000000000000000000000000000000000000000000000000000006000527f08ba3617671847c1c169da222a5bc01cfdefcc3c4f1e5525214a474479c89123805490911663bc197c81179055565b7fbb39ebb37e60fb5d606ffdb749d2336e56b88e6c88c4bd6513b308f643186eed8282604051610c819291906134b3565b600054610100900460ff1661231e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161079e565b610bfc816125f5565b6001600160a01b0381163b6123a45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161079e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6123fb83612620565b6000825111806124085750805b15610892576114a48383612660565b600061246c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661276b9092919063ffffffff16565b805190915015610892578080602001905181019061248a9190613503565b6108925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161079e565b60007fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d82148061254b57507f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc82145b8061257557507f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b82145b8061259f57507f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c82145b806125c957507f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e77808837282145b806108035750507ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc1490565b610bfc30827f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada336118ea565b61262981612327565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6126df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161079e565b600080846001600160a01b0316846040516126fa919061353e565b600060405180830381855af49150503d8060008114612735576040519150601f19603f3d011682016040523d82523d6000602084013e61273a565b606091505b509150915061276282826040518060600160405280602781526020016135516027913961277a565b95945050505050565b6060610a5a8484600085612793565b60608315612789575081610940565b6109408383612885565b60608247101561280b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161079e565b600080866001600160a01b03168587604051612827919061353e565b60006040518083038185875af1925050503d8060008114612864576040519150601f19603f3d011682016040523d82523d6000602084013e612869565b606091505b509150915061287a878383876128af565b979650505050505050565b8151156128955781518083602001fd5b8060405162461bcd60e51b815260040161079e9190612c80565b6060831561291e578251600003612917576001600160a01b0385163b6129175760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079e565b5081610a5a565b610a5a8383612885565b6001600160e01b031981168114610bfc57600080fd5b60006020828403121561295057600080fd5b813561094081612928565b60008083601f84011261296d57600080fd5b50813567ffffffffffffffff81111561298557600080fd5b60208301915083602082850101111561299d57600080fd5b9250929050565b600080602083850312156129b757600080fd5b823567ffffffffffffffff8111156129ce57600080fd5b6129da8582860161295b565b90969095509350505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112612a0d57600080fd5b813567ffffffffffffffff80821115612a2857612a286129e6565b604051601f8301601f19908116603f01168101908282118183101715612a5057612a506129e6565b81604052838152866020858801011115612a6957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612a9c57600080fd5b82359150602083013567ffffffffffffffff811115612aba57600080fd5b612ac6858286016129fc565b9150509250929050565b6001600160a01b0381168114610bfc57600080fd5b600080600060408486031215612afa57600080fd5b8335612b0581612ad0565b9250602084013567ffffffffffffffff80821115612b2257600080fd5b818601915086601f830112612b3657600080fd5b813581811115612b4557600080fd5b876020606083028501011115612b5a57600080fd5b6020830194508093505050509250925092565b60008060008060808587031215612b8357600080fd5b8435612b8e81612ad0565b93506020850135612b9e81612ad0565b925060408501359150606085013567ffffffffffffffff811115612bc157600080fd5b612bcd878288016129fc565b91505092959194509250565b600060208284031215612beb57600080fd5b813561094081612ad0565b60008060408385031215612c0957600080fd5b8235612c1481612ad0565b9150602083013567ffffffffffffffff811115612aba57600080fd5b60005b83811015612c4b578181015183820152602001612c33565b50506000910152565b60008151808452612c6c816020860160208601612c30565b601f01601f19169290920160200192915050565b6020815260006109406020830184612c54565b60008060008060608587031215612ca957600080fd5b8435612cb481612ad0565b935060208501359250604085013567ffffffffffffffff811115612cd757600080fd5b612ce38782880161295b565b95989497509550505050565b600080600060608486031215612d0457600080fd5b8335612d0f81612928565b92506020840135612d1f81612928565b91506040840135612d2f81612928565b809150509250925092565b60008060008060608587031215612d5057600080fd5b84359350602085013567ffffffffffffffff80821115612d6f57600080fd5b818701915087601f830112612d8357600080fd5b813581811115612d9257600080fd5b8860208260051b8501011115612da757600080fd5b95986020929092019750949560400135945092505050565b600081518084526020808501808196508360051b8101915082860160005b85811015612e07578284038952612df5848351612c54565b98850198935090840190600101612ddd565b5091979650505050505050565b604081526000612e276040830185612dbf565b90508260208301529392505050565b60008060008060808587031215612e4c57600080fd5b8435612e5781612ad0565b93506020850135612e6781612ad0565b9250604085013591506060850135612e7e81612ad0565b939692955090935050565b600080600060608486031215612e9e57600080fd5b8335612ea981612ad0565b92506020840135612eb981612ad0565b929592945050506040919091013590565b60008060208385031215612edd57600080fd5b823567ffffffffffffffff80821115612ef557600080fd5b818501915085601f830112612f0957600080fd5b813581811115612f1857600080fd5b86602060a083028501011115612f2d57600080fd5b60209290920196919550909350505050565b60008060008060008060808789031215612f5857600080fd5b863567ffffffffffffffff80821115612f7057600080fd5b612f7c8a838b0161295b565b909850965060208901359150612f9182612ad0565b909450604088013590612fa382612ad0565b90935060608801359080821115612fb957600080fd5b50612fc689828a0161295b565b979a9699509497509295939492505050565b6001600160a01b0383168152604060208201526000610a5a6040830184612c54565b828152604060208201526000610a5a6040830184612c54565b60006020828403121561302557600080fd5b815161094081612928565b634e487b7160e01b600052603260045260246000fd5b80356003811061305557600080fd5b919050565b60006060828403121561306c57600080fd5b6040516060810181811067ffffffffffffffff8211171561308f5761308f6129e6565b60405261309b83613046565b815260208301356130ab81612ad0565b60208201526040928301359281019290925250919050565b634e487b7160e01b600052602160045260246000fd5b600181811c908216806130ed57607f821691505b60208210810361310d57634e487b7160e01b600052602260045260246000fd5b50919050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b838152604060208201526000610a57604083018486613113565b60008235605e1983360301811261316e57600080fd5b9190910192915050565b6000808335601e1984360301811261318f57600080fd5b83018035915067ffffffffffffffff8211156131aa57600080fd5b60200191503681900382131561299d57600080fd5b8183823760009101908152919050565b6000826131ec57634e487b7160e01b600052601260045260246000fd5b500490565b60006080820187835260206080818501528187835260a08501905060a08860051b86010192508860005b898110156132ee577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608786030183528135605e198c360301811261325e57600080fd5b8b016060813561326d81612ad0565b6001600160a01b03168752818601358688015260408083013536849003601e1901811261329957600080fd5b90920186810192903567ffffffffffffffff8111156132b757600080fd5b8036038413156132c657600080fd5b82828a01526132d8838a018286613113565b985050509385019350509083019060010161321b565b50505050846040840152828103606084015261330a8185612dbf565b98975050505050505050565b600060a0828403121561332857600080fd5b60405160a0810181811067ffffffffffffffff8211171561334b5761334b6129e6565b60405261335783613046565b8152602083013561336781612ad0565b6020820152604083013561337a81612ad0565b6040820152606083013561338d81612ad0565b60608201526080928301359281019290925250919050565b601f82111561089257600081815260208120601f850160051c810160208610156133cc5750805b601f850160051c820191505b818110156133eb578281556001016133d8565b505050505050565b67ffffffffffffffff83111561340b5761340b6129e6565b61341f8361341983546130d9565b836133a5565b6000601f841160018114613453576000851561343b5750838201355b600019600387901b1c1916600186901b178355610a10565b600083815260209020601f19861690835b828110156134845786850135825560209485019460019092019101613464565b50868210156134a15760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b602081526000610a5a602083018486613113565b60006001600160a01b038087168352808616602084015250836040830152608060608301526134f96080830184612c54565b9695505050505050565b60006020828403121561351557600080fd5b8151801515811461094057600080fd5b60006020828403121561353757600080fd5b5051919050565b6000825161316e818460208701612c3056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200c168e950345d0d51e5072f0d6741c8fffb903a88e5f4d9ae41a3c116b51090b64736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106101d15760003560e01c8063829331a1116100f7578063d96054c411610095578063e978afe511610064578063e978afe5146106b2578063eafb8b06146106d2578063ee57e36f146106f2578063fdef91061461071257610210565b8063d96054c41461060a578063da7422281461062a578063e2e355631461064a578063e306bee71461067e57610210565b8063c71bf324116100d1578063c71bf3241461057d578063c9dbc2a4146105ab578063ce1b815f146105cb578063d68bad2c146105ea57610210565b8063829331a114610516578063bfe07da61461054a578063c4a501451461055d57610210565b80632675fdd01161016f5780633e2ab0d91161013e5780633e2ab0d9146104ac5780634f1ef286146104cc57806352d1902d146104df5780637034731b146104f457610210565b80632675fdd0146103ff57806326875b1f1461041f5780633659cfe614610453578063388da9341461047357610210565b80631080f99b116101ab5780631080f99b146103505780631626ba7e1461037257806322844d04146103ab57806324b4d73f146103cb57610210565b806301ffc9a7146102a55780630729d054146102da57806309e56b141461031c57610210565b3661021057604080513381523460208201527f62c2c8e34665db7c56b2cabd7f5fb9702ccd352ffa8150147e450797e9f8e8f3910160405180910390a1005b34801561021c57600080fd5b50600036606060006102706000356001600160e01b03191685858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061073292505050565b604080516001600160e01b03198316602082015291925001604051602081830303815290604052915050915050805190602001f35b3480156102b157600080fd5b506102c56102c036600461293e565b610809565b60405190151581526020015b60405180910390f35b3480156102e657600080fd5b5061030e7fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d81565b6040519081526020016102d1565b34801561032857600080fd5b5061030e7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3381565b34801561035c57600080fd5b5061037061036b3660046129a4565b61085e565b005b34801561037e57600080fd5b5061039261038d366004612a89565b610897565b6040516001600160e01b031990911681526020016102d1565b3480156103b757600080fd5b506103706103c6366004612ae5565b610947565b3480156103d757600080fd5b5061030e7f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc81565b34801561040b57600080fd5b506102c561041a366004612b6d565b610a17565b34801561042b57600080fd5b5061030e7ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc81565b34801561045f57600080fd5b5061037061046e366004612bd9565b610a62565b34801561047f57600080fd5b5061012d54610494906001600160a01b031681565b6040516001600160a01b0390911681526020016102d1565b3480156104b857600080fd5b506103706104c7366004612bd9565b610bff565b6103706104da366004612bf6565b610c8d565b3480156104eb57600080fd5b5061030e610e1b565b34801561050057600080fd5b50610509610ee0565b6040516102d19190612c80565b34801561052257600080fd5b5061030e7f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c81565b610370610558366004612c93565b610f73565b34801561056957600080fd5b50610370610578366004612cef565b6110ad565b34801561058957600080fd5b5061059d610598366004612d3a565b611160565b6040516102d1929190612e14565b3480156105b757600080fd5b506103706105c6366004612e36565b611439565b3480156105d757600080fd5b5061012e546001600160a01b0316610494565b3480156105f657600080fd5b50610370610605366004612e89565b61146f565b34801561061657600080fd5b50610370610625366004612e89565b6114aa565b34801561063657600080fd5b50610370610645366004612bd9565b6114df565b34801561065657600080fd5b5061030e7f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e77808837281565b34801561068a57600080fd5b5061030e7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b81565b3480156106be57600080fd5b506103706106cd366004612eca565b611512565b3480156106de57600080fd5b506103706106ed366004612f3f565b611619565b3480156106fe57600080fd5b5061037061070d3660046129a4565b6117e0565b34801561071e57600080fd5b506102c561072d366004612b6d565b611814565b6001600160e01b0319808316600090815260fb6020526040812054909160e09190911b9081166107a7576040517f54bdcc3e0000000000000000000000000000000000000000000000000000000081526001600160e01b03198086166004830152821660248201526044015b60405180910390fd5b837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f4792cb6e46e49876374bea490ba23274bacea6b84c216a64f47abab54027589b33856040516107f8929190612fd8565b60405180910390a290505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806108035750506001600160e01b03191660009081526033602052604090205460ff1690565b7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b61088881611822565b61089283836118aa565b505050565b61012d546000906001600160a01b03166108b357506000610803565b61012d546040517f1626ba7e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690631626ba7e906108ff9086908690600401612ffa565b602060405180830381865afa15801561091c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109409190613013565b9392505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361097181611822565b60005b82811015610a1057600084848381811061099057610990613030565b9050606002018036038101906109a6919061305a565b90506000815160028111156109bd576109bd6130c3565b036109da576109d586826020015183604001516118ea565b610a07565b6001815160028111156109ef576109ef6130c3565b03610a0757610a0786826020015183604001516118f7565b50600101610974565b5050505050565b6000610a25858585856119fe565b80610a3e5750610a3e856001600160a01b0385856119fe565b80610a575750610a576001600160a01b038585856119fe565b90505b949350505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610b005760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c0000000000000000000000000000000000000000606482015260840161079e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614610bd75760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f78790000000000000000000000000000000000000000606482015260840161079e565b610be081611b72565b60408051600080825260208201909252610bfc91839190611b9c565b50565b7f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e778088372610c2981611822565b61012d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527f3b25c5d3870ec0eac28822b177f18c9130233ade5b7f857c6a224a507c37fc4e906020015b60405180910390a15050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d2b5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c0000000000000000000000000000000000000000606482015260840161079e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610d867f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614610e025760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f78790000000000000000000000000000000000000000606482015260840161079e565b610e0b82611b72565b610e1782826001611b9c565b5050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ebb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161079e565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b606061012f8054610ef0906130d9565b80601f0160208091040260200160405190810160405280929190818152602001828054610f1c906130d9565b8015610f695780601f10610f3e57610100808354040283529160200191610f69565b820191906000526020600020905b815481529060010190602001808311610f4c57829003601f168201915b5050505050905090565b82600003610fad576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841661100257823414610ffd576040517f1abd56100000000000000000000000000000000000000000000000000000000081526004810184905234602482015260440161079e565b611058565b3415611043576040517f1abd56100000000000000000000000000000000000000000000000000000000081526000600482015234602482015260440161079e565b6110586001600160a01b038516333086611d3c565b836001600160a01b0316336001600160a01b03167f2bc500cf071be2d1c1458ed6ff484cd4db4345ada8943dee7ff29e7af3558f7685858560405161109f9392919061313e565b60405180910390a350505050565b7ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc6110d781611822565b6110e084611dc4565b6001600160e01b03198316600090815260fb60205260409020805463ffffffff191660e084901c179055604080516001600160e01b0319808716825280861660208301528416918101919091527ffc72fd547553f7a663e0048e590afc9c47b56a4242e960f31cf4c62e23d308b99060600160405180910390a150505050565b606060007fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d61118e81611822565b6101008511156111ca576040517f11c763d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8467ffffffffffffffff8111156111e3576111e36129e6565b60405190808252806020026020018201604052801561121657816020015b60608152602001906001900390816112015790505b50925060008060005b878110156113e3575a92506000808a8a8481811061123f5761123f613030565b90506020028101906112519190613158565b61125f906020810190612bd9565b6001600160a01b03168b8b8581811061127a5761127a613030565b905060200281019061128c9190613158565b602001358c8c868181106112a2576112a2613030565b90506020028101906112b49190613158565b6112c2906040810190613178565b6040516112d09291906131bf565b60006040518083038185875af1925050503d806000811461130d576040519150601f19603f3d011682016040523d82523d6000602084013e611312565b606091505b50915091505a9350600160ff84161b89166113665781611361576040517fa6a7dbbd0000000000000000000000000000000000000000000000000000000081526004810184905260240161079e565b6113bb565b816113bb576113766040866131cf565b8410156113af576040517f1c26714c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160ff84161b871896505b808884815181106113ce576113ce613030565b6020908102919091010152505060010161121f565b50336001600160a01b03167fd0de18eab8dc7532aab0fc4eb308477031cabf9fd312ea3b3a5fe9aa45ac8ed78a8a8a888a6040516114259594939291906131f1565b60405180910390a250505094509492505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361146381611822565b610a1085858585611e43565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361149981611822565b6114a48484846118ea565b50505050565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada336114d481611822565b6114a48484846118f7565b7f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c61150981611822565b610e1782612101565b7f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada3361153c81611822565b60005b828110156114a457600084848381811061155b5761155b613030565b905060a002018036038101906115719190613316565b9050600081516002811115611588576115886130c3565b036115a9576115a48160200151826040015183608001516118ea565b611610565b6001815160028111156115be576115be6130c3565b036115da576115a48160200151826040015183608001516118f7565b6002815160028111156115ef576115ef6130c3565b03611610576116108160200151826040015183608001518460600151611e43565b5060010161153f565b600054610100900460ff16158080156116395750600054600160ff909116105b806116535750303b158015611653575060005460ff166001145b6116c55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161079e565b6000805460ff1916600117905580156116e8576000805461ff0019166101001790555b6117117f9385547e00000000000000000000000000000000000000000000000000000000611dc4565b61173a7f1626ba7e00000000000000000000000000000000000000000000000000000000611dc4565b6117637f7034731b00000000000000000000000000000000000000000000000000000000611dc4565b61176b612163565b6117758787612270565b61177e84612101565b61178883836118aa565b611791856122a1565b80156117d7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b7f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b61180a81611822565b6108928383612270565b6000610a5785858585610a17565b6118653033836000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a1792505050565b610bfc576040517f1e09743f0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810182905260640161079e565b61012f6118b88284836133f3565b507fe9b617ecb5f63f6a9ccd8d4d5fa0d7b2ef9b17ce3f48e6b135808d6a40e677428282604051610c819291906134b3565b6108928383836002611e43565b604080517f5045524d495353494f4e000000000000000000000000000000000000000000006020808301919091526bffffffffffffffffffffffff19606086811b8216602a85015287901b16603e83015260528083018590528351808403909101815260729092019092528051910120600090600081815260c960205260409020549091506001600160a01b0316156114a457600081815260c96020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916905590516001600160a01b038681168252851691339185917f3ca48185ec3f6e47e24db18b13f1c65b1ce05da1659f9c1c4fe717dda5f67524910160405180910390a450505050565b60008060c96000611a838888886040517f5045524d495353494f4e0000000000000000000000000000000000000000000060208201526bffffffffffffffffffffffff19606084811b8216602a84015285901b16603e820152605281018290526000906072016040516020818303038152906040528051906020012090509392505050565b81526020810191909152604001600020546001600160a01b0316905080611aae576000915050610a5a565b6001196001600160a01b03821601611aca576001915050610a5a565b6040517f2675fdd00000000000000000000000000000000000000000000000000000000081526001600160a01b03821690632675fdd090611b159089908990899089906004016134c7565b602060405180830381865afa925050508015611b4e575060408051601f3d908101601f19168201909252611b4b91810190613503565b60015b15611b66578015611b6457600192505050610a5a565b505b50600095945050505050565b7f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc610e1781611822565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611bcf5761089283612327565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611c29575060408051601f3d908101601f19168201909252611c2691810190613525565b60015b611c9b5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f742055555053000000000000000000000000000000000000606482015260840161079e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114611d305760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c65555549440000000000000000000000000000000000000000000000606482015260840161079e565b506108928383836123f2565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526114a4908590612417565b6001600160e01b03198082169003611e1e5760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640161079e565b6001600160e01b0319166000908152603360205260409020805460ff19166001179055565b6001600160a01b03848116148015611e6357506001600160a01b03838116145b15611e9a576040517f85f1ba9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038481161480611eb957506001600160a01b03838116145b15611f73576000611ec9836124fc565b90507f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada33831480611ef65750805b15611f2d576040517f24159e5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001196001600160a01b03831601611f71576040517f92ab7d0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b604080517f5045524d495353494f4e000000000000000000000000000000000000000000006020808301919091526bffffffffffffffffffffffff19606087811b8216602a85015288901b16603e83015260528083018690528351808403909101815260729092019092528051910120600090600081815260c960205260409020549091506001600160a01b0316828161208c57600083815260c96020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038581169190911790915582518a8216815287821692810192909252881691339188917f0f579ad49235a8c1fd9041427e7067b1eb10926bbed380bf6fabc73e0e807644910160405180910390a46117d7565b806001600160a01b0316826001600160a01b0316146117d7576040517f0b98789e0000000000000000000000000000000000000000000000000000000081526001600160a01b03808916600483015280881660248301526044820187905280841660648301528216608482015260a40161079e565b61012e805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527fd91237492a9e30cd2faf361fc103998a382ff0ec2b1b07dc1cbebb76ae2f1ea29060200160405180910390a150565b61218c7f150b7a0200000000000000000000000000000000000000000000000000000000611dc4565b6121b57f4e2312e000000000000000000000000000000000000000000000000000000000611dc4565b60fb6020527f5a08f87af82de422c581ce019b2e54a9c17372e9cba575ae0470ba2482d63686805463ffffffff1990811663150b7a02179091557fe1cfe341950d56d8854f782066100d5ae1d5930cdb4949b973e554a343efc6c38054821663f23a6e611790557fbc197c81000000000000000000000000000000000000000000000000000000006000527f08ba3617671847c1c169da222a5bc01cfdefcc3c4f1e5525214a474479c89123805490911663bc197c81179055565b7fbb39ebb37e60fb5d606ffdb749d2336e56b88e6c88c4bd6513b308f643186eed8282604051610c819291906134b3565b600054610100900460ff1661231e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161079e565b610bfc816125f5565b6001600160a01b0381163b6123a45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161079e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6123fb83612620565b6000825111806124085750805b15610892576114a48383612660565b600061246c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661276b9092919063ffffffff16565b805190915015610892578080602001905181019061248a9190613503565b6108925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161079e565b60007fbf04b4486c9663d805744005c3da000eda93de6e3308a4a7a812eb565327b78d82148061254b57507f1f53edd44352e5d15bad2b29233baa93bcd595e09457780bc7c5445bbbe751cc82145b8061257557507f4707e94b25cfce1a7c363508fbb838c35864388ad77284b248282b9746982b9b82145b8061259f57507f06d294bc8cbad2e393408b20dd019a772661f60b8d633e56761157cb1ec85f8c82145b806125c957507f0dcbfb19b09fb8ff4e9af583d4b8e9c8127cc1b26529b4d96dd3b7e77808837282145b806108035750507ffaf505be9907aa6951c2ebe5b0312f4980e14f21912ed355372103cc8bd683bc1490565b610bfc30827f815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada336118ea565b61262981612327565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6126df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161079e565b600080846001600160a01b0316846040516126fa919061353e565b600060405180830381855af49150503d8060008114612735576040519150601f19603f3d011682016040523d82523d6000602084013e61273a565b606091505b509150915061276282826040518060600160405280602781526020016135516027913961277a565b95945050505050565b6060610a5a8484600085612793565b60608315612789575081610940565b6109408383612885565b60608247101561280b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161079e565b600080866001600160a01b03168587604051612827919061353e565b60006040518083038185875af1925050503d8060008114612864576040519150601f19603f3d011682016040523d82523d6000602084013e612869565b606091505b509150915061287a878383876128af565b979650505050505050565b8151156128955781518083602001fd5b8060405162461bcd60e51b815260040161079e9190612c80565b6060831561291e578251600003612917576001600160a01b0385163b6129175760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079e565b5081610a5a565b610a5a8383612885565b6001600160e01b031981168114610bfc57600080fd5b60006020828403121561295057600080fd5b813561094081612928565b60008083601f84011261296d57600080fd5b50813567ffffffffffffffff81111561298557600080fd5b60208301915083602082850101111561299d57600080fd5b9250929050565b600080602083850312156129b757600080fd5b823567ffffffffffffffff8111156129ce57600080fd5b6129da8582860161295b565b90969095509350505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112612a0d57600080fd5b813567ffffffffffffffff80821115612a2857612a286129e6565b604051601f8301601f19908116603f01168101908282118183101715612a5057612a506129e6565b81604052838152866020858801011115612a6957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612a9c57600080fd5b82359150602083013567ffffffffffffffff811115612aba57600080fd5b612ac6858286016129fc565b9150509250929050565b6001600160a01b0381168114610bfc57600080fd5b600080600060408486031215612afa57600080fd5b8335612b0581612ad0565b9250602084013567ffffffffffffffff80821115612b2257600080fd5b818601915086601f830112612b3657600080fd5b813581811115612b4557600080fd5b876020606083028501011115612b5a57600080fd5b6020830194508093505050509250925092565b60008060008060808587031215612b8357600080fd5b8435612b8e81612ad0565b93506020850135612b9e81612ad0565b925060408501359150606085013567ffffffffffffffff811115612bc157600080fd5b612bcd878288016129fc565b91505092959194509250565b600060208284031215612beb57600080fd5b813561094081612ad0565b60008060408385031215612c0957600080fd5b8235612c1481612ad0565b9150602083013567ffffffffffffffff811115612aba57600080fd5b60005b83811015612c4b578181015183820152602001612c33565b50506000910152565b60008151808452612c6c816020860160208601612c30565b601f01601f19169290920160200192915050565b6020815260006109406020830184612c54565b60008060008060608587031215612ca957600080fd5b8435612cb481612ad0565b935060208501359250604085013567ffffffffffffffff811115612cd757600080fd5b612ce38782880161295b565b95989497509550505050565b600080600060608486031215612d0457600080fd5b8335612d0f81612928565b92506020840135612d1f81612928565b91506040840135612d2f81612928565b809150509250925092565b60008060008060608587031215612d5057600080fd5b84359350602085013567ffffffffffffffff80821115612d6f57600080fd5b818701915087601f830112612d8357600080fd5b813581811115612d9257600080fd5b8860208260051b8501011115612da757600080fd5b95986020929092019750949560400135945092505050565b600081518084526020808501808196508360051b8101915082860160005b85811015612e07578284038952612df5848351612c54565b98850198935090840190600101612ddd565b5091979650505050505050565b604081526000612e276040830185612dbf565b90508260208301529392505050565b60008060008060808587031215612e4c57600080fd5b8435612e5781612ad0565b93506020850135612e6781612ad0565b9250604085013591506060850135612e7e81612ad0565b939692955090935050565b600080600060608486031215612e9e57600080fd5b8335612ea981612ad0565b92506020840135612eb981612ad0565b929592945050506040919091013590565b60008060208385031215612edd57600080fd5b823567ffffffffffffffff80821115612ef557600080fd5b818501915085601f830112612f0957600080fd5b813581811115612f1857600080fd5b86602060a083028501011115612f2d57600080fd5b60209290920196919550909350505050565b60008060008060008060808789031215612f5857600080fd5b863567ffffffffffffffff80821115612f7057600080fd5b612f7c8a838b0161295b565b909850965060208901359150612f9182612ad0565b909450604088013590612fa382612ad0565b90935060608801359080821115612fb957600080fd5b50612fc689828a0161295b565b979a9699509497509295939492505050565b6001600160a01b0383168152604060208201526000610a5a6040830184612c54565b828152604060208201526000610a5a6040830184612c54565b60006020828403121561302557600080fd5b815161094081612928565b634e487b7160e01b600052603260045260246000fd5b80356003811061305557600080fd5b919050565b60006060828403121561306c57600080fd5b6040516060810181811067ffffffffffffffff8211171561308f5761308f6129e6565b60405261309b83613046565b815260208301356130ab81612ad0565b60208201526040928301359281019290925250919050565b634e487b7160e01b600052602160045260246000fd5b600181811c908216806130ed57607f821691505b60208210810361310d57634e487b7160e01b600052602260045260246000fd5b50919050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b838152604060208201526000610a57604083018486613113565b60008235605e1983360301811261316e57600080fd5b9190910192915050565b6000808335601e1984360301811261318f57600080fd5b83018035915067ffffffffffffffff8211156131aa57600080fd5b60200191503681900382131561299d57600080fd5b8183823760009101908152919050565b6000826131ec57634e487b7160e01b600052601260045260246000fd5b500490565b60006080820187835260206080818501528187835260a08501905060a08860051b86010192508860005b898110156132ee577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608786030183528135605e198c360301811261325e57600080fd5b8b016060813561326d81612ad0565b6001600160a01b03168752818601358688015260408083013536849003601e1901811261329957600080fd5b90920186810192903567ffffffffffffffff8111156132b757600080fd5b8036038413156132c657600080fd5b82828a01526132d8838a018286613113565b985050509385019350509083019060010161321b565b50505050846040840152828103606084015261330a8185612dbf565b98975050505050505050565b600060a0828403121561332857600080fd5b60405160a0810181811067ffffffffffffffff8211171561334b5761334b6129e6565b60405261335783613046565b8152602083013561336781612ad0565b6020820152604083013561337a81612ad0565b6040820152606083013561338d81612ad0565b60608201526080928301359281019290925250919050565b601f82111561089257600081815260208120601f850160051c810160208610156133cc5750805b601f850160051c820191505b818110156133eb578281556001016133d8565b505050505050565b67ffffffffffffffff83111561340b5761340b6129e6565b61341f8361341983546130d9565b836133a5565b6000601f841160018114613453576000851561343b5750838201355b600019600387901b1c1916600186901b178355610a10565b600083815260209020601f19861690835b828110156134845786850135825560209485019460019092019101613464565b50868210156134a15760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b602081526000610a5a602083018486613113565b60006001600160a01b038087168352808616602084015250836040830152608060608301526134f96080830184612c54565b9695505050505050565b60006020828403121561351557600080fd5b8151801515811461094057600080fd5b60006020828403121561353757600080fd5b5051919050565b6000825161316e818460208701612c3056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200c168e950345d0d51e5072f0d6741c8fffb903a88e5f4d9ae41a3c116b51090b64736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/packages/subgraph/manifest/data/arbitrum-rinkeby.json b/packages/subgraph/manifest/data/arbitrum-rinkeby.json deleted file mode 100644 index 4de84e363..000000000 --- a/packages/subgraph/manifest/data/arbitrum-rinkeby.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "info": "# Do not edit subgraph.yaml,this is a generated file. \n# Instead, edit subgraph.placeholder.yaml and run: yarn manifest", - "network": "arbitrum-rinkeby", - "dataSources": { - "DAORegistry": { - "name": "DAORegistry", - "address": "0xcDbC588740854c24EF8edd50d91d3E511f984501", - "startBlock": 13456350 - }, - "PluginRepoRegistry": { - "name": "PluginRepoRegistry", - "address": "0x2B8C4DD137104d1E869105cd0106e7D9EF955BfE", - "startBlock": 7727664 - }, - "PluginSetupProcessor": { - "name": "PluginRepoRegistry", - "address": "0x2B8C4DD137104d1E869105cd0106e7D9EF955BfE", - "startBlock": 7727664 - } - } -} \ No newline at end of file diff --git a/packages/subgraph/manifest/data/goerli.json b/packages/subgraph/manifest/data/goerli.json index 30d4c6a55..d8da150c2 100644 --- a/packages/subgraph/manifest/data/goerli.json +++ b/packages/subgraph/manifest/data/goerli.json @@ -12,10 +12,12 @@ "address": "0x970Eb7Dd57c9F0dc4c5a10c06653d1103946b508", "startBlock": 8548226 }, - "PluginSetupProcessor": { - "name": "PluginSetupProcessor", - "address": "0xE8B5d8D66a02CD1b9Bd32a4064D7ABa45F51305e", - "startBlock": 8548226 - } + "PluginSetupProcessors": [ + { + "name": "PluginSetupProcessor", + "address": "0xE8B5d8D66a02CD1b9Bd32a4064D7ABa45F51305e", + "startBlock": 8548226 + } + ] } } diff --git a/packages/subgraph/manifest/data/localhost.json b/packages/subgraph/manifest/data/localhost.json index 2d3ff2f64..6ba4cfede 100644 --- a/packages/subgraph/manifest/data/localhost.json +++ b/packages/subgraph/manifest/data/localhost.json @@ -12,10 +12,12 @@ "address": "0x2B8C4DD137104d1E869105cd0106e7D9EF955BfE", "startBlock": 7727664 }, - "PluginSetupProcessor": { - "name": "PluginRepoRegistry", - "address": "0x2B8C4DD137104d1E869105cd0106e7D9EF955BfE", - "startBlock": 7727664 - } + "PluginSetupProcessors": [ + { + "name": "PluginSetupProcessor", + "address": "0x2B8C4DD137104d1E869105cd0106e7D9EF955BfE", + "startBlock": 7727664 + } + ] } } diff --git a/packages/subgraph/manifest/data/mainnet.json b/packages/subgraph/manifest/data/mainnet.json index 72f369c5f..36188fed4 100644 --- a/packages/subgraph/manifest/data/mainnet.json +++ b/packages/subgraph/manifest/data/mainnet.json @@ -12,10 +12,12 @@ "address": "0x5B3B36BdC9470963A2734D6a0d2F6a64C21C159f", "startBlock": 16721812 }, - "PluginSetupProcessor": { - "name": "PluginSetupProcessor", - "address": "0xE978942c691e43f65c1B7c7F8f1dc8cDF061B13f", - "startBlock": 16721812 - } + "PluginSetupProcessors": [ + { + "name": "PluginSetupProcessor", + "address": "0xE978942c691e43f65c1B7c7F8f1dc8cDF061B13f", + "startBlock": 16721812 + } + ] } } diff --git a/packages/subgraph/manifest/data/mumbai.json b/packages/subgraph/manifest/data/mumbai.json index 27e6b6d9d..fe4003fdc 100644 --- a/packages/subgraph/manifest/data/mumbai.json +++ b/packages/subgraph/manifest/data/mumbai.json @@ -12,10 +12,12 @@ "address": "0xc796bB1AfEBc56daDF6CAcD2aDa78055e5381971", "startBlock": 33514164 }, - "PluginSetupProcessor": { - "name": "PluginRepoRegistry", - "address": "0x9227b311C5cecB416707F1C8B7Ca1b52649AabEc", - "startBlock": 33514164 - } + "PluginSetupProcessors": [ + { + "name": "PluginSetupProcessor", + "address": "0x9227b311C5cecB416707F1C8B7Ca1b52649AabEc", + "startBlock": 33514164 + } + ] } -} \ No newline at end of file +} diff --git a/packages/subgraph/manifest/data/polygon.json b/packages/subgraph/manifest/data/polygon.json index e63ae837d..162073c83 100644 --- a/packages/subgraph/manifest/data/polygon.json +++ b/packages/subgraph/manifest/data/polygon.json @@ -6,16 +6,18 @@ "name": "DAORegistry", "address": "0x96E54098317631641703404C06A5afAD89da7373", "startBlock": 40817440 - }, - "PluginRepoRegistry": { - "name": "PluginRepoRegistry", - "address": "0xA03C2182af8eC460D498108C92E8638a580b94d4", - "startBlock": 40817440 - }, - "PluginSetupProcessor": { - "name": "PluginRepoRegistry", + } + }, + "PluginRepoRegistry": { + "name": "PluginRepoRegistry", + "address": "0xA03C2182af8eC460D498108C92E8638a580b94d4", + "startBlock": 40817440 + }, + "PluginSetupProcessors": [ + { + "name": "PluginSetupProcessor", "address": "0x879D9dfe3F36d7684BeC1a2bB4Aa8E8871A7245B", "startBlock": 40817440 } - } + ] } diff --git a/packages/subgraph/manifest/subgraph.placeholder.yaml b/packages/subgraph/manifest/subgraph.placeholder.yaml index 447e38ce3..a1b33a79c 100644 --- a/packages/subgraph/manifest/subgraph.placeholder.yaml +++ b/packages/subgraph/manifest/subgraph.placeholder.yaml @@ -6,7 +6,7 @@ schema: file: ./schema.graphql dataSources: - kind: ethereum/contract - name: DAORegistry + name: {{dataSources.DAORegistry.name}} network: {{network}} source: abi: DAORegistry @@ -28,7 +28,7 @@ dataSources: handler: handleDAORegistered file: ./src/registries/daoRegistry.ts - kind: ethereum/contract - name: PluginRepoRegistry + name: {{dataSources.PluginRepoRegistry.name}} network: {{network}} source: abi: PluginRepoRegistry @@ -47,13 +47,14 @@ dataSources: - event: PluginRepoRegistered(string,address) handler: handlePluginRepoRegistered file: ./src/registries/pluginRepoRegistry.ts + {{#dataSources.PluginSetupProcessors}} - kind: ethereum/contract - name: PluginSetupProcessor + name: {{name}} network: {{network}} source: abi: PluginSetupProcessor - address: '{{dataSources.PluginSetupProcessor.address}}' - startBlock: {{dataSources.PluginSetupProcessor.startBlock}} + address: '{{address}}' + startBlock: {{startBlock}} mapping: kind: ethereum/events apiVersion: 0.0.5 @@ -87,10 +88,11 @@ dataSources: - event: UninstallationApplied(indexed address,indexed address,bytes32) handler: handleUninstallationApplied file: ./src/plugin/pluginSetupProcessor.ts + {{/dataSources.PluginSetupProcessors}} # templates templates: # DAO - - name: DaoTemplate + - name: DaoTemplateV1_0_0 kind: ethereum/contract network: {{network}} source: @@ -99,7 +101,7 @@ templates: kind: ethereum/events apiVersion: 0.0.5 language: wasm/assemblyscript - file: ./src/dao/dao.ts + file: ./src/dao/dao_v1_0_0.ts entities: - Dao abis: @@ -114,7 +116,7 @@ templates: - name: AddresslistVoting file: $ARAGON_OSX_MODULE/artifacts/src/plugins/governance/majority-voting/addresslist/AddresslistVoting.sol/AddresslistVoting.json - name: DAO - file: $ARAGON_OSX_MODULE/artifacts/src/core/dao/DAO.sol/DAO.json + file: $ARAGON_OSX_MODULE/../subgraph/abis/DAO_v1_0_0.json - name: CallbackHandler file: $ARAGON_OSX_MODULE/artifacts/src/core/utils/CallbackHandler.sol/CallbackHandler.json eventHandlers: @@ -138,6 +140,24 @@ templates: handler: handleStandardCallbackRegistered - event: SignatureValidatorSet(address) handler: handleSignatureValidatorSet + - name: DaoTemplateV1_2_0 + kind: ethereum/contract + network: {{network}} + source: + abi: DAO + mapping: + kind: ethereum/events + apiVersion: 0.0.5 + language: wasm/assemblyscript + file: ./src/dao/dao_v1_2_0.ts + entities: + - Dao + abis: + - name: DAO + file: $ARAGON_OSX_MODULE/artifacts/src/core/dao/DAO.sol/DAO.json + eventHandlers: + - event: Executed(indexed address,bytes32,(address,uint256,bytes)[],uint256,uint256,bytes[]) + handler: handleExecuted # TokenVoting (package) - name: TokenVoting kind: ethereum/contract @@ -152,6 +172,8 @@ templates: entities: - Dao abis: + - name: ERC20 + file: $ARAGON_OSX_MODULE/artifacts/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.json - name: TokenVoting file: $ARAGON_OSX_MODULE/artifacts/src/plugins/governance/majority-voting/token/TokenVoting.sol/TokenVoting.json eventHandlers: @@ -255,6 +277,8 @@ templates: entities: - Dao abis: + - name: DAO + file: $ARAGON_OSX_MODULE/artifacts/src/core/dao/DAO.sol/DAO.json - name: Admin file: $ARAGON_OSX_MODULE/artifacts/src/plugins/governance/admin/Admin.sol/Admin.json eventHandlers: diff --git a/packages/subgraph/src/dao/dao.ts b/packages/subgraph/src/dao/dao_v1_0_0.ts similarity index 71% rename from packages/subgraph/src/dao/dao.ts rename to packages/subgraph/src/dao/dao_v1_0_0.ts index 583713b32..5332176fe 100644 --- a/packages/subgraph/src/dao/dao.ts +++ b/packages/subgraph/src/dao/dao_v1_0_0.ts @@ -11,7 +11,7 @@ import { SignatureValidatorSet, StandardCallbackRegistered, CallbackReceived -} from '../../generated/templates/DaoTemplate/DAO'; +} from '../../generated/templates/DaoTemplateV1_0_0/DAO'; import { Dao, ContractPermissionId, @@ -23,18 +23,11 @@ import { import {ADDRESS_ZERO} from '../utils/constants'; -import {handleERC721Action, handleERC721Received} from '../utils/tokens/erc721'; -import {handleERC20Action, handleERC20Deposit} from '../utils/tokens/erc20'; -import {handleNativeAction, handleNativeDeposit} from '../utils/tokens/eth'; -import { - ERC20_transfer, - ERC20_transferFrom, - ERC721_safeTransferFromNoData, - ERC721_safeTransferFromWithData, - ERC721_transferFrom, - onERC721Received -} from '../utils/tokens/common'; -import {updateProposalWithFailureMap} from './utils'; +import {handleERC721Received} from '../utils/tokens/erc721'; +import {handleERC20Deposit} from '../utils/tokens/erc20'; +import {handleNativeDeposit} from '../utils/tokens/eth'; +import {onERC721Received} from '../utils/tokens/common'; +import {handleAction, updateProposalWithFailureMap} from './utils'; export function handleMetadataSet(event: MetadataSet): void { let daoId = event.address.toHexString(); @@ -111,71 +104,7 @@ export function handleExecuted(event: Executed): void { let actions = event.params.actions; for (let index = 0; index < actions.length; index++) { - const action = actions[index]; - - let actionId = proposalId.concat('_').concat(index.toString()); - let actionEntity = Action.load(actionId); - - // In case the execute on the dao is called by the address - // That we don't currently index for the actions in the subgraph, - // we fallback and still create an action. - // NOTE that it's important to generate action id differently to not allow overwriting. - if (!actionEntity) { - actionEntity = new Action(actionId); - actionEntity.to = action.to; - actionEntity.value = action.value; - actionEntity.data = action.data; - actionEntity.proposal = proposalId; - actionEntity.dao = event.address.toHexString(); - } - - actionEntity.execResult = event.params.execResults[index]; - actionEntity.save(); - - if (action.data.toHexString() == '0x' && action.value.gt(BigInt.zero())) { - handleNativeAction( - event.address, - action.to, - action.value, - 'Native Token Withdraw', - proposalId, - index, - event - ); - continue; - } - - let methodSig = action.data.toHexString().slice(0, 10); - - // Since ERC721 transferFrom and ERC20 transferFrom have the same signature, - // The below first checks if it's ERC721 by calling `supportsInterface` and then - // moves to ERC20 check. Currently, if `action` is transferFrom, it will still check - // both `handleERC721Action`, `handleERC20Action`. - if ( - methodSig == ERC721_transferFrom || - methodSig == ERC721_safeTransferFromNoData || - methodSig == ERC721_safeTransferFromWithData - ) { - handleERC721Action( - action.to, - event.address, - action.data, - proposalId, - index, - event - ); - } - - if (methodSig == ERC20_transfer || methodSig == ERC20_transferFrom) { - handleERC20Action( - action.to, - event.address, - proposalId, - action.data, - index, - event - ); - } + handleAction(actions[index], proposalId, index, event); } } diff --git a/packages/subgraph/src/dao/dao_v1_2_0.ts b/packages/subgraph/src/dao/dao_v1_2_0.ts new file mode 100644 index 000000000..0cc6a90a4 --- /dev/null +++ b/packages/subgraph/src/dao/dao_v1_2_0.ts @@ -0,0 +1,41 @@ +import {TransactionActionsProposal} from '../../generated/schema'; +import { + Executed, + ExecutedActionsStruct +} from '../../generated/templates/DaoTemplateV1_2_0/DAO'; +import {handleAction} from './utils'; + +export function handleExecuted(event: Executed): void { + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()); + + proposalId = proposalId + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + let proposal = new TransactionActionsProposal(proposalId); + proposal.dao = event.address.toHexString(); + proposal.createdAt = event.block.timestamp; + proposal.endDate = event.block.timestamp; + proposal.startDate = event.block.timestamp; + proposal.creator = event.params.actor; + proposal.executionTxHash = event.transaction.hash; + proposal.allowFailureMap = event.params.allowFailureMap; + proposal.executed = true; + proposal.failureMap = event.params.failureMap; + proposal.save(); + + let actions = event.params.actions; + + for (let index = 0; index < actions.length; index++) { + handleAction( + actions[index], + proposalId, + index, + event + ); + } +} diff --git a/packages/subgraph/src/dao/utils.ts b/packages/subgraph/src/dao/utils.ts index dce33f804..123a16958 100644 --- a/packages/subgraph/src/dao/utils.ts +++ b/packages/subgraph/src/dao/utils.ts @@ -1,20 +1,25 @@ +import {BigInt} from '@graphprotocol/graph-ts'; import { - Address, - BigInt, - ByteArray, - Bytes, - ethereum -} from '@graphprotocol/graph-ts'; -import { + Action, AddresslistVotingProposal, AdminProposal, MultisigProposal, - TokenVotingProposal, - TransactionActionsProposal + TokenVotingProposal } from '../../generated/schema'; -import {Admin, TokenVoting} from '../../generated/templates'; - -import {ADDRESS_ZERO} from '../utils/constants'; +import { + Executed, + ExecutedActionsStruct +} from '../../generated/templates/DaoTemplateV1_0_0/DAO'; +import { + ERC721_transferFrom, + ERC721_safeTransferFromNoData, + ERC721_safeTransferFromWithData, + ERC20_transfer, + ERC20_transferFrom +} from '../utils/tokens/common'; +import {handleERC20Action} from '../utils/tokens/erc20'; +import {handleERC721Action} from '../utils/tokens/erc721'; +import {handleNativeAction} from '../utils/tokens/eth'; // AssemblyScript struggles having mutliple return types. Due to this, // The below seems most effective way. @@ -52,3 +57,72 @@ export function updateProposalWithFailureMap( return false; } + +export function handleAction< + T extends ExecutedActionsStruct, + R extends Executed +>(action: T, proposalId: string, index: i32, event: R): void { + let actionId = proposalId.concat('_').concat(index.toString()); + let actionEntity = Action.load(actionId); + + // In case the execute on the dao is called by the address + // That we don't currently index for the actions in the subgraph, + // we fallback and still create an action. + // NOTE that it's important to generate action id differently to not allow overwriting. + if (!actionEntity) { + actionEntity = new Action(actionId); + actionEntity.to = action.to; + actionEntity.value = action.value; + actionEntity.data = action.data; + actionEntity.proposal = proposalId; + actionEntity.dao = event.address.toHexString(); + } + + actionEntity.execResult = event.params.execResults[index]; + actionEntity.save(); + + if (action.data.toHexString() == '0x' && action.value.gt(BigInt.zero())) { + handleNativeAction( + event.address, + action.to, + action.value, + 'Native Token Withdraw', + proposalId, + index, + event + ); + return; + } + + let methodSig = action.data.toHexString().slice(0, 10); + + // Since ERC721 transferFrom and ERC20 transferFrom have the same signature, + // The below first checks if it's ERC721 by calling `supportsInterface` and then + // moves to ERC20 check. Currently, if `action` is transferFrom, it will still check + // both `handleERC721Action`, `handleERC20Action`. + if ( + methodSig == ERC721_transferFrom || + methodSig == ERC721_safeTransferFromNoData || + methodSig == ERC721_safeTransferFromWithData + ) { + handleERC721Action( + action.to, + event.address, + action.data, + proposalId, + index, + event + ); + } + + if (methodSig == ERC20_transfer || methodSig == ERC20_transferFrom) { + handleERC20Action( + action.to, + event.address, + proposalId, + action.data, + index, + event + ); + } +} diff --git a/packages/subgraph/src/packages/addresslist/addresslist-voting.ts b/packages/subgraph/src/packages/addresslist/addresslist-voting.ts index 3250d4aca..2e4a3b290 100644 --- a/packages/subgraph/src/packages/addresslist/addresslist-voting.ts +++ b/packages/subgraph/src/packages/addresslist/addresslist-voting.ts @@ -187,7 +187,9 @@ export function handleVoteCast(event: VoteCast): void { // Used when proposal has not ended. proposalEntity.earlyExecutable = - supportThresholdReachedEarly && minParticipationReached; + supportThresholdReachedEarly && + minParticipationReached && + proposalEntity.votingMode === VOTING_MODES.get(1); } proposalEntity.save(); } diff --git a/packages/subgraph/src/packages/admin/adminMembers.ts b/packages/subgraph/src/packages/admin/adminMembers.ts index 034424066..4f6f2019a 100644 --- a/packages/subgraph/src/packages/admin/adminMembers.ts +++ b/packages/subgraph/src/packages/admin/adminMembers.ts @@ -3,7 +3,7 @@ import { Administrator, AdministratorAdminPlugin } from '../../../generated/schema'; -import {Granted, Revoked} from '../../../generated/templates/DaoTemplate/DAO'; +import {Granted, Revoked} from '../../../generated/templates/Admin/DAO'; export function handleGranted(event: Granted): void { if ( diff --git a/packages/subgraph/src/packages/token/governance-erc20.ts b/packages/subgraph/src/packages/token/governance-erc20.ts index 813e5353d..1691663c7 100644 --- a/packages/subgraph/src/packages/token/governance-erc20.ts +++ b/packages/subgraph/src/packages/token/governance-erc20.ts @@ -1,7 +1,7 @@ import {Address, BigInt, dataSource} from '@graphprotocol/graph-ts'; import {TokenVotingMember} from '../../../generated/schema'; -import {Transfer} from '../../../generated/templates/DaoTemplate/ERC20'; +import {Transfer} from '../../../generated/templates/TokenVoting/ERC20'; function getOrCreateMember(user: Address, pluginId: string): TokenVotingMember { let id = user diff --git a/packages/subgraph/src/packages/token/token-voting.ts b/packages/subgraph/src/packages/token/token-voting.ts index 2e899bb9f..13fd95895 100644 --- a/packages/subgraph/src/packages/token/token-voting.ts +++ b/packages/subgraph/src/packages/token/token-voting.ts @@ -202,7 +202,9 @@ export function handleVoteCast(event: VoteCast): void { // Used when proposal has not ended. proposalEntity.earlyExecutable = - supportThresholdReachedEarly && minParticipationReached; + supportThresholdReachedEarly && + minParticipationReached && + proposalEntity.votingMode === VOTING_MODES.get(1); } proposalEntity.save(); } diff --git a/packages/subgraph/src/plugin/utils.ts b/packages/subgraph/src/plugin/utils.ts index 6e61e7014..03b539cc7 100644 --- a/packages/subgraph/src/plugin/utils.ts +++ b/packages/subgraph/src/plugin/utils.ts @@ -5,12 +5,11 @@ import { ethereum, crypto, ByteArray, - log } from '@graphprotocol/graph-ts'; import {TokenVoting as TokenVotingContract} from '../../generated/templates/TokenVoting/TokenVoting'; import {AddresslistVoting as AddresslistVotingContract} from '../../generated/templates/AddresslistVoting/AddresslistVoting'; -import {ERC165 as ERC165Contract} from '../../generated/templates/DaoTemplate/ERC165'; +import {ERC165 as ERC165Contract} from '../../generated/PluginSetupProcessor/ERC165'; import { TokenVoting, AddresslistVoting, diff --git a/packages/subgraph/src/registries/daoRegistry.ts b/packages/subgraph/src/registries/daoRegistry.ts index 52535d3ac..219a08965 100644 --- a/packages/subgraph/src/registries/daoRegistry.ts +++ b/packages/subgraph/src/registries/daoRegistry.ts @@ -1,5 +1,5 @@ import {DAORegistered} from '../../generated/DAORegistry/DAORegistry'; -import {DaoTemplate} from '../../generated/templates'; +import {DaoTemplateV1_0_0, DaoTemplateV1_2_0} from '../../generated/templates'; import {Dao} from '../../generated/schema'; import {dataSource} from '@graphprotocol/graph-ts'; @@ -21,7 +21,8 @@ export function handleDAORegistered(event: DAORegistered): void { entity.createdAt = event.block.timestamp; // subscribe to templates - DaoTemplate.create(event.params.dao); + DaoTemplateV1_0_0.create(event.params.dao); + DaoTemplateV1_2_0.create(event.params.dao); entity.save(); } diff --git a/packages/subgraph/src/utils/tokens/erc20.ts b/packages/subgraph/src/utils/tokens/erc20.ts index 9432021ac..b001268d6 100644 --- a/packages/subgraph/src/utils/tokens/erc20.ts +++ b/packages/subgraph/src/utils/tokens/erc20.ts @@ -4,7 +4,7 @@ import { ERC20Contract, ERC20Transfer } from '../../../generated/schema'; -import {ERC20} from '../../../generated/templates/DaoTemplate/ERC20'; +import {ERC20} from '../../../generated/templates/DaoTemplateV1_0_0/ERC20'; import {ERC20_transfer, ERC20_transferFrom, getTransferId} from './common'; export function fetchERC20(address: Address): ERC20Contract | null { diff --git a/packages/subgraph/src/utils/tokens/erc721.ts b/packages/subgraph/src/utils/tokens/erc721.ts index 1a09aec1a..55476b51d 100644 --- a/packages/subgraph/src/utils/tokens/erc721.ts +++ b/packages/subgraph/src/utils/tokens/erc721.ts @@ -4,7 +4,7 @@ import { ERC721Contract, ERC721Transfer } from '../../../generated/schema'; -import {ERC721} from '../../../generated/templates/DaoTemplate/ERC721'; +import {ERC721} from '../../../generated/templates/DaoTemplateV1_0_0/ERC721'; import {supportsInterface} from '../erc165'; import {DECODE_OFFSET, getTransferId, TransferType} from './common'; import { diff --git a/packages/subgraph/tests/admin/utils.ts b/packages/subgraph/tests/admin/utils.ts index da03320e3..4274e9354 100644 --- a/packages/subgraph/tests/admin/utils.ts +++ b/packages/subgraph/tests/admin/utils.ts @@ -5,7 +5,7 @@ import { ProposalCreated, ProposalExecuted } from '../../generated/templates/Admin/Admin'; -import {Granted, Revoked} from '../../generated/templates/DaoTemplate/DAO'; +import {Granted, Revoked} from '../../generated/templates/Admin/DAO'; import {ADDRESS_ZERO} from '../constants'; // events diff --git a/packages/subgraph/tests/dao/dao.test.ts b/packages/subgraph/tests/dao/dao_v1_0_0.test.ts similarity index 97% rename from packages/subgraph/tests/dao/dao.test.ts rename to packages/subgraph/tests/dao/dao_v1_0_0.test.ts index ee18bfbc9..5c3aab97b 100644 --- a/packages/subgraph/tests/dao/dao.test.ts +++ b/packages/subgraph/tests/dao/dao_v1_0_0.test.ts @@ -18,7 +18,7 @@ import { handleSignatureValidatorSet, handleStandardCallbackRegistered, handleCallbackReceived -} from '../../src/dao/dao'; +} from '../../src/dao/dao_v1_0_0'; import { DAO_ADDRESS, ADDRESS_ONE, @@ -44,7 +44,8 @@ import { createTrustedForwarderSetEvent, createSignatureValidatorSetEvent, createStandardCallbackRegisteredEvent, - getSupportsInterface + getSupportsInterface, + encodeWithFunctionSelector } from './utils'; import { ERC20_transfer, @@ -59,8 +60,7 @@ import { ERC721Balance, TransactionActionsProposal } from '../../generated/schema'; -import {Executed} from '../../generated/templates/DaoTemplate/DAO'; -import {getProposalId} from '../../src/utils/proposals'; +import {Executed} from '../../generated/templates/DaoTemplateV1_0_0/DAO'; const eq = assert.fieldEquals; @@ -68,28 +68,6 @@ let daoId = Address.fromString(DAO_ADDRESS).toHexString(); let tokenId = Address.fromString(DAO_TOKEN_ADDRESS).toHexString(); let balanceId = daoId.concat('_').concat(tokenId); -function encodeWithFunctionSelector( - tuple: Array, - funcSelector: string, - isDynamic: boolean = false -): Bytes { - // ethereum.decode inside subgraph doesn't append 0x00...20 while the actual event - // thrown from the real network includes this appended offset. Due to this, mappings contain - // extra logic(appending the offset to the actual calldata in order to do ethereum.decode). - // Due to this, from the tests, we need to append it as well. Note that this rule only applies - // when the emitted event contains at least 1 dynamic type. - let index = isDynamic == true ? 66 : 2; - - let calldata = ethereum - .encode(ethereum.Value.fromTuple(changetype(tuple)))! - .toHexString() - .substring(index); - - let functionData = funcSelector.concat(calldata); - - return Bytes.fromHexString(functionData); -} - // create Executed event with multiple actions function createExecutedEvent( tuple: ethereum.Value[][], @@ -121,13 +99,14 @@ function createExecutedEvent( } } - let event = createNewExecutedEvent( + let event = createNewExecutedEvent( Address.fromHexString(CONTRACT_ADDRESS).toHexString(), ZERO_BYTES32, actions, BigInt.fromString(failureMap), execResults, - Address.fromHexString(DAO_ADDRESS).toHexString() + Address.fromHexString(DAO_ADDRESS).toHexString(), + null ); return event; diff --git a/packages/subgraph/tests/dao/dao_v1_2_0.test.ts b/packages/subgraph/tests/dao/dao_v1_2_0.test.ts new file mode 100644 index 000000000..5708451d8 --- /dev/null +++ b/packages/subgraph/tests/dao/dao_v1_2_0.test.ts @@ -0,0 +1,667 @@ +import {ethereum, Bytes, Address, BigInt} from '@graphprotocol/graph-ts'; +import { + describe, + test, + beforeEach, + afterEach, + clearStore, + assert, + beforeAll +} from 'matchstick-as'; +import { + TransactionActionsProposal, + Action, + ERC721Balance +} from '../../generated/schema'; +import {Executed} from '../../generated/templates/DaoTemplateV1_2_0/DAO'; +import {handleExecuted} from '../../src/dao/dao_v1_2_0'; +import { + ERC20_transfer, + getTransferId, + ERC20_transferFrom, + ERC721_transferFrom, + ERC721_safeTransferFromWithData +} from '../../src/utils/tokens/common'; +import { + DAO_ADDRESS, + DAO_TOKEN_ADDRESS, + ERC20_AMOUNT_HALF, + ADDRESS_THREE, + ERC20_AMOUNT_FULL, + CONTRACT_ADDRESS, + ZERO_BYTES32 +} from '../constants'; +import {createDummyActions, createTokenCalls} from '../utils'; +import { + createNewExecutedEvent, + encodeWithFunctionSelector, + getBalanceOf, + getSupportsInterface +} from './utils'; + +const eq = assert.fieldEquals; +let daoId = Address.fromString(DAO_ADDRESS).toHexString(); +let tokenId = Address.fromString(DAO_TOKEN_ADDRESS).toHexString(); +let balanceId = daoId.concat('_').concat(tokenId); + +describe('handleExecuted', () => { + afterEach(() => { + clearStore(); + }); + + test('successfuly creates action and proposal if not found', () => { + let tuple: Array = [ethereum.Value.fromString('')]; + let selector = '0x11111111'; + + let execResults = [ + Bytes.fromHexString('0x11'), + Bytes.fromHexString('0x22') + ]; + + let allowFailureMap = '2'; + let failureMap = '2'; + + let event = createExecutedEvent( + [tuple, tuple], + [selector, selector], + allowFailureMap, + false, + execResults, + failureMap + ); + + handleExecuted(event); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + assert.entityCount('TransactionActionsProposal', 1); + assert.entityCount('Action', 2); + + eq('TransactionActionsProposal', proposalId, 'id', proposalId); + eq('TransactionActionsProposal', proposalId, 'failureMap', failureMap); + eq( + 'TransactionActionsProposal', + proposalId, + 'allowFailureMap', + allowFailureMap + ); + + for (let i = 0; i < event.params.actions.length; i++) { + let actionId = proposalId.concat('_').concat(i.toString()); + + eq('Action', actionId, 'id', actionId); + eq('Action', actionId, 'execResult', execResults[i].toHexString()); + eq('Action', actionId, 'dao', DAO_ADDRESS); + eq('Action', actionId, 'proposal', proposalId); + eq( + 'Action', + actionId, + 'data', + encodeWithFunctionSelector(tuple, selector).toHexString() + ); + } + }); + + test('successfuly updates action and proposal if found', () => { + let tuple: Array = [ethereum.Value.fromString('')]; + let selector = '0x11111111'; + let execResult = Bytes.fromHexString('0x11'); + let allowFailureMap = '2'; + let failureMap = '2'; + + let event = createExecutedEvent( + [tuple], + [selector], + allowFailureMap, + false, + [execResult], + failureMap + ); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + let actionId = proposalId.concat('_').concat('0'); + + // create proposal + let proposal = new TransactionActionsProposal(proposalId); + proposal.dao = event.address.toHexString(); + proposal.createdAt = event.block.timestamp; + proposal.endDate = event.block.timestamp; + proposal.startDate = event.block.timestamp; + proposal.allowFailureMap = BigInt.fromString(allowFailureMap); + proposal.creator = event.params.actor; + proposal.executionTxHash = event.transaction.hash; + proposal.executed = true; + proposal.save(); + + // create action + let action = new Action(actionId); + action.to = Address.fromString(DAO_TOKEN_ADDRESS); + action.data = Bytes.fromHexString('0x'); + action.value = BigInt.zero(); + action.dao = event.address.toHexString(); + action.proposal = proposal.id; + action.save(); + + // Check that before `handleExecute`, execResults are empty + assert.entityCount('Action', 1); + assert.entityCount('TransactionActionsProposal', 1); + assert.assertTrue(action.execResult === null); + assert.assertTrue(proposal.failureMap === null); + + handleExecuted(event); + + // The action and proposal count should be the same. + assert.entityCount('Action', 1); + assert.entityCount('TransactionActionsProposal', 1); + + eq('Action', actionId, 'id', actionId); + eq('Action', actionId, 'execResult', execResult.toHexString()); + + eq('TransactionActionsProposal', proposalId, 'id', proposalId); + eq('TransactionActionsProposal', proposalId, 'failureMap', failureMap); + eq( + 'TransactionActionsProposal', + proposalId, + 'allowFailureMap', + allowFailureMap + ); + }); + + describe('ERC20 action', () => { + beforeAll(() => { + createTokenCalls(DAO_TOKEN_ADDRESS, 'name', 'symbol', '6', '10'); + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_ADDRESS, ERC20_AMOUNT_HALF); + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_TOKEN_ADDRESS, ERC20_AMOUNT_HALF); + + // Even though for ERC20, there's no need to be mocking supportsInterface of ERC721, + // The below is still required. This is caused by the fact that ERC20's transferFrom + // And ERC721 transferFrom exactly have the same signature and mapping can't detect, + // So the test should be agnostic even if ERC721 check gets called first from mapping. + // Otherwise, without the below mock and if ERC721 check is called from mapping, the test + // Would fail. https://github.com/LimeChain/matchstick/issues/278#issuecomment-1426884510 + getSupportsInterface(DAO_TOKEN_ADDRESS, '0x01ffc9a7', false); + getSupportsInterface(DAO_TOKEN_ADDRESS, '80ac58cd', false); + getSupportsInterface(DAO_TOKEN_ADDRESS, '00000000', false); + }); + + describe('ERC20 transfer action', () => { + test('creates entities with correct values', () => { + let transferToken = BigInt.fromU32(10); + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(transferToken) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC20_transfer], + '0', + false, + [], + '0' + ); + + handleExecuted(event); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + let txHash = event.transaction.hash; + let logIndex = event.transactionLogIndex; + let timestamp = event.block.timestamp; + + let transferId = getTransferId(txHash, logIndex, 0); + + // check ERC20Contract entity + eq('ERC20Contract', tokenId, 'id', tokenId); + eq('ERC20Contract', tokenId, 'name', 'name'); + eq('ERC20Contract', tokenId, 'symbol', 'symbol'); + assert.entityCount('ERC20Contract', 1); + + // check ERC20Balance entity + eq('ERC20Balance', balanceId, 'id', balanceId); + eq('ERC20Balance', balanceId, 'token', tokenId); + eq('ERC20Balance', balanceId, 'dao', daoId); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_HALF); + eq('ERC20Balance', balanceId, 'lastUpdated', timestamp.toString()); + assert.entityCount('ERC20Balance', 1); + + // Check ERC20Transfer + eq('ERC20Transfer', transferId, 'id', transferId); + eq('ERC20Transfer', transferId, 'dao', daoId); + eq('ERC20Transfer', transferId, 'amount', transferToken.toString()); + eq('ERC20Transfer', transferId, 'from', DAO_ADDRESS); + eq('ERC20Transfer', transferId, 'to', ADDRESS_THREE); + eq('ERC20Transfer', transferId, 'proposal', proposalId); + eq('ERC20Transfer', transferId, 'type', 'Withdraw'); + eq('ERC20Transfer', transferId, 'txHash', txHash.toHexString()); + eq('ERC20Transfer', transferId, 'createdAt', timestamp.toString()); + assert.entityCount('ERC20Transfer', 1); + }); + + test('correctly handles multiple events and updates balance', () => { + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(BigInt.fromU32(10)) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC20_transfer], + '0', + false, + [], + '0' + ); + + handleExecuted(event); + + // After 1st event + assert.entityCount('ERC20Contract', 1); + assert.entityCount('ERC20Transfer', 1); + assert.entityCount('ERC20Balance', 1); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_HALF); + + // Mock balance of with different amount + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_ADDRESS, ERC20_AMOUNT_FULL); + + // Change log index so it will enforce to generate new transferId + // to make sure we can aserst ERC20Transfer to be 2. + event.transactionLogIndex = BigInt.fromI32(2); + handleExecuted(event); + + // After 2nd event + assert.entityCount('ERC20Contract', 1); + assert.entityCount('ERC20Transfer', 2); + assert.entityCount('ERC20Balance', 1); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_FULL); + + // Mock balance to get it back to the same before running this test + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_ADDRESS, ERC20_AMOUNT_HALF); + }); + }); + + describe('ERC20(transferFrom) action', () => { + test('creates entities with correct values', () => { + let transferToken = BigInt.fromU32(10); + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)), + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(transferToken) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC20_transferFrom], + '0', + false, + [], + '0' + ); + + handleExecuted(event); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + let txHash = event.transaction.hash; + let logIndex = event.transactionLogIndex; + let timestamp = event.block.timestamp; + + let transferId = getTransferId(txHash, logIndex, 0); + + // check ERC20Contract entity + eq('ERC20Contract', tokenId, 'id', tokenId); + eq('ERC20Contract', tokenId, 'name', 'name'); + eq('ERC20Contract', tokenId, 'symbol', 'symbol'); + assert.entityCount('ERC20Contract', 1); + + // check ERC20Balance entity + eq('ERC20Balance', balanceId, 'id', balanceId); + eq('ERC20Balance', balanceId, 'token', tokenId); + eq('ERC20Balance', balanceId, 'dao', daoId); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_HALF); + eq('ERC20Balance', balanceId, 'lastUpdated', timestamp.toString()); + assert.entityCount('ERC20Balance', 1); + + // Check ERC20Transfer + eq('ERC20Transfer', transferId, 'id', transferId); + eq('ERC20Transfer', transferId, 'dao', daoId); + eq('ERC20Transfer', transferId, 'amount', transferToken.toString()); + eq('ERC20Transfer', transferId, 'from', DAO_ADDRESS); + eq('ERC20Transfer', transferId, 'to', ADDRESS_THREE); + eq('ERC20Transfer', transferId, 'proposal', proposalId); + eq('ERC20Transfer', transferId, 'type', 'Withdraw'); + eq('ERC20Transfer', transferId, 'txHash', txHash.toHexString()); + eq('ERC20Transfer', transferId, 'createdAt', timestamp.toString()); + assert.entityCount('ERC20Transfer', 1); + }); + + test('correctly handles multiple events and update balance', () => { + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)), + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(BigInt.fromU32(10)) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC20_transferFrom], + '0', + false, + [], + '0' + ); + + handleExecuted(event); + + assert.entityCount('ERC20Contract', 1); + assert.entityCount('ERC20Balance', 1); + assert.entityCount('ERC20Transfer', 1); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_HALF); + + // Mock balance of with different amount + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_ADDRESS, ERC20_AMOUNT_FULL); + + // Change log index so it will enforce to generate new transferId + // to make sure we can aserst ERC20Transfer to be 2. + event.transactionLogIndex = BigInt.fromI32(2); + handleExecuted(event); + + assert.entityCount('ERC20Contract', 1); + assert.entityCount('ERC20Balance', 1); + assert.entityCount('ERC20Transfer', 2); + eq('ERC20Balance', balanceId, 'balance', ERC20_AMOUNT_FULL); + + // Mock balance to get it back to the same before running this test + getBalanceOf(DAO_TOKEN_ADDRESS, DAO_ADDRESS, ERC20_AMOUNT_HALF); + }); + }); + }); + + describe('ERC721 action', () => { + beforeAll(() => { + createTokenCalls(DAO_TOKEN_ADDRESS, 'name', 'symbol', null, null); + + getSupportsInterface(DAO_TOKEN_ADDRESS, '0x01ffc9a7', true); + getSupportsInterface(DAO_TOKEN_ADDRESS, '80ac58cd', true); + getSupportsInterface(DAO_TOKEN_ADDRESS, '00000000', false); + }); + + beforeEach(() => { + let entity = new ERC721Balance(balanceId); + entity.dao = daoId; + entity.tokenIds = [ + BigInt.fromI32(4), + BigInt.fromI32(8), + BigInt.fromI32(12) + ]; + entity.lastUpdated = BigInt.fromI32(2); + entity.token = tokenId; + entity.save(); + }); + + describe('ERC721 transferFrom', () => { + test('create entities with correct values', () => { + let transferToKen = BigInt.fromU32(8); + + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)), + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(transferToKen) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC721_transferFrom], + '0', + false, + [], + '0' + ); + + let txHash = event.transaction.hash; + let logIndex = event.transactionLogIndex; + let timestamp = event.block.timestamp; + + let transferId = getTransferId(txHash, logIndex, 0); + + handleExecuted(event); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + // check ERC721Contract entity + eq('ERC721Contract', tokenId, 'id', tokenId); + eq('ERC721Contract', tokenId, 'name', 'name'); + eq('ERC721Contract', tokenId, 'symbol', 'symbol'); + assert.entityCount('ERC721Contract', 1); + + // check ERC721Balance entity + eq('ERC721Balance', balanceId, 'id', balanceId); + eq('ERC721Balance', balanceId, 'token', tokenId); + eq('ERC721Balance', balanceId, 'dao', daoId); + eq('ERC721Balance', balanceId, 'tokenIds', '[4, 12]'); + eq('ERC721Balance', balanceId, 'lastUpdated', timestamp.toString()); + assert.entityCount('ERC721Balance', 1); + + // Check ERC721Transfer + eq('ERC721Transfer', transferId, 'id', transferId); + eq('ERC721Transfer', transferId, 'dao', daoId); + eq('ERC721Transfer', transferId, 'tokenId', transferToKen.toString()); + eq('ERC721Transfer', transferId, 'from', DAO_ADDRESS); + eq('ERC721Transfer', transferId, 'to', ADDRESS_THREE); + eq('ERC721Transfer', transferId, 'proposal', proposalId); + eq('ERC721Transfer', transferId, 'type', 'Withdraw'); + eq('ERC721Transfer', transferId, 'txHash', txHash.toHexString()); + eq('ERC721Transfer', transferId, 'createdAt', timestamp.toString()); + assert.entityCount('ERC721Transfer', 1); + }); + + test('correctly handles multiple events and updates balance', () => { + let from = ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)); + let to = ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)); + let transferToken1 = ethereum.Value.fromUnsignedBigInt( + BigInt.fromU32(8) + ); + let transferToken2 = ethereum.Value.fromUnsignedBigInt( + BigInt.fromU32(12) + ); + + let tuple1: Array = [from, to, transferToken1]; + let tuple2: Array = [from, to, transferToken2]; + + let event = createExecutedEvent( + [tuple1, tuple2], + [ERC721_transferFrom, ERC721_transferFrom], + '0', + false, + [], + '0' + ); + + handleExecuted(event); + + assert.entityCount('ERC721Contract', 1); + assert.entityCount('ERC721Balance', 1); + assert.entityCount('ERC721Transfer', 2); + eq('ERC721Balance', balanceId, 'tokenIds', '[4]'); + }); + }); + + describe('ERC721 safeTransferFrom with data', () => { + test('create entities with correct values', () => { + let transferToKen = BigInt.fromU32(8); + + let tupleArray: Array = [ + ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)), + ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)), + ethereum.Value.fromUnsignedBigInt(transferToKen), + ethereum.Value.fromBytes(Bytes.fromHexString('0x')) + ]; + + let event = createExecutedEvent( + [tupleArray], + [ERC721_safeTransferFromWithData], + '0', + true, + [], + '0' + ); + + let txHash = event.transaction.hash; + let logIndex = event.transactionLogIndex; + let timestamp = event.block.timestamp; + + let transferId = getTransferId(txHash, logIndex, 0); + + handleExecuted(event); + + let proposalId = event.params.actor + .toHexString() + .concat('_') + .concat(event.params.callId.toHexString()) + .concat('_') + .concat(event.transaction.hash.toHexString()) + .concat('_') + .concat(event.transactionLogIndex.toHexString()); + + // check ERC721Contract entity + eq('ERC721Contract', tokenId, 'id', tokenId); + eq('ERC721Contract', tokenId, 'name', 'name'); + eq('ERC721Contract', tokenId, 'symbol', 'symbol'); + assert.entityCount('ERC721Contract', 1); + + // check ERC721Balance entity + eq('ERC721Balance', balanceId, 'id', balanceId); + eq('ERC721Balance', balanceId, 'token', tokenId); + eq('ERC721Balance', balanceId, 'dao', daoId); + eq('ERC721Balance', balanceId, 'tokenIds', '[4, 12]'); + eq('ERC721Balance', balanceId, 'lastUpdated', timestamp.toString()); + assert.entityCount('ERC721Balance', 1); + + // Check ERC721Transfer + eq('ERC721Transfer', transferId, 'id', transferId); + eq('ERC721Transfer', transferId, 'dao', daoId); + eq('ERC721Transfer', transferId, 'tokenId', transferToKen.toString()); + eq('ERC721Transfer', transferId, 'from', DAO_ADDRESS); + eq('ERC721Transfer', transferId, 'to', ADDRESS_THREE); + eq('ERC721Transfer', transferId, 'proposal', proposalId); + eq('ERC721Transfer', transferId, 'type', 'Withdraw'); + eq('ERC721Transfer', transferId, 'txHash', txHash.toHexString()); + eq('ERC721Transfer', transferId, 'createdAt', timestamp.toString()); + assert.entityCount('ERC721Transfer', 1); + }); + + test('correctly handles multiple events and updates balance', () => { + let from = ethereum.Value.fromAddress(Address.fromString(DAO_ADDRESS)); + let to = ethereum.Value.fromAddress(Address.fromString(ADDRESS_THREE)); + let data = ethereum.Value.fromBytes(Bytes.fromHexString('0x')); + + let transferToken1 = ethereum.Value.fromUnsignedBigInt( + BigInt.fromU32(8) + ); + let transferToken2 = ethereum.Value.fromUnsignedBigInt( + BigInt.fromU32(12) + ); + + let tuple1: Array = [from, to, transferToken1, data]; + let tuple2: Array = [from, to, transferToken2, data]; + + let event = createExecutedEvent( + [tuple1, tuple2], + [ERC721_safeTransferFromWithData, ERC721_safeTransferFromWithData], + '0', + true, + [], + '0' + ); + + handleExecuted(event); + + assert.entityCount('ERC721Contract', 1); + assert.entityCount('ERC721Balance', 1); + assert.entityCount('ERC721Transfer', 2); + eq('ERC721Balance', balanceId, 'tokenIds', '[4]'); + }); + }); + }); +}); + +// create Executed event with multiple actions +function createExecutedEvent( + tuple: ethereum.Value[][], + selectors: string[], + allowFailureMap: string, + isDynamic: boolean, + execResults: Bytes[], + failureMap: string +): Executed { + let actions: ethereum.Tuple[] = []; + for (let i = 0; i < selectors.length; i++) { + let functionData = encodeWithFunctionSelector( + tuple[i], + selectors[i], + isDynamic + ); + + let action = createDummyActions( + DAO_TOKEN_ADDRESS, + '0', + functionData.toHexString() + ); + + actions.push(action[0]); + } + + if (execResults.length == 0) { + for (let i = 0; i < actions.length; i++) { + execResults[i] = Bytes.fromHexString('0x11'); + } + } + + let event = createNewExecutedEvent( + Address.fromHexString(CONTRACT_ADDRESS).toHexString(), + ZERO_BYTES32, + actions, + BigInt.fromString(failureMap), + execResults, + Address.fromHexString(DAO_ADDRESS).toHexString(), + BigInt.fromString(allowFailureMap) + ); + + return event; +} diff --git a/packages/subgraph/tests/dao/permission-manager.test.ts b/packages/subgraph/tests/dao/permission-manager.test.ts index 34127cc6c..d1a3a42e0 100644 --- a/packages/subgraph/tests/dao/permission-manager.test.ts +++ b/packages/subgraph/tests/dao/permission-manager.test.ts @@ -1,7 +1,7 @@ import {assert, clearStore, test} from 'matchstick-as/assembly/index'; import {Address, ByteArray, Bytes, crypto} from '@graphprotocol/graph-ts'; -import {handleGranted, handleRevoked} from '../../src/dao/dao'; +import {handleGranted, handleRevoked} from '../../src/dao/dao_v1_0_0'; import {Permission, ContractPermissionId} from '../../generated/schema'; import { DAO_ADDRESS, diff --git a/packages/subgraph/tests/dao/utils.ts b/packages/subgraph/tests/dao/utils.ts index 2e90f04e0..9ed7a7db4 100644 --- a/packages/subgraph/tests/dao/utils.ts +++ b/packages/subgraph/tests/dao/utils.ts @@ -13,7 +13,7 @@ import { SignatureValidatorSet, StandardCallbackRegistered, CallbackReceived -} from '../../generated/templates/DaoTemplate/DAO'; +} from '../../generated/templates/DaoTemplateV1_0_0/DAO'; // events @@ -251,15 +251,16 @@ export function createNewRevokedEvent( return newGrantedEvent; } -export function createNewExecutedEvent( +export function createNewExecutedEvent( actor: string, callId: string, actions: ethereum.Tuple[], failureMap: BigInt, execResults: Bytes[], - contractAddress: string -): Executed { - let newExecutedEvent = changetype(newMockEvent()); + contractAddress: string, + allowFailureMap: BigInt | null // used from DAO V1.2 and higher +): T { + let newExecutedEvent = changetype(newMockEvent()); newExecutedEvent.address = Address.fromString(contractAddress); newExecutedEvent.parameters = []; @@ -277,6 +278,14 @@ export function createNewExecutedEvent( ethereum.Value.fromTupleArray(actions) ); + let allowFailureMapParam: ethereum.EventParam | null = null; + if (allowFailureMap) { + allowFailureMapParam = new ethereum.EventParam( + 'allowFailureMap', + ethereum.Value.fromUnsignedBigInt(allowFailureMap) + ); + } + let failureMapParam = new ethereum.EventParam( 'failureMap', ethereum.Value.fromUnsignedBigInt(failureMap) @@ -290,6 +299,11 @@ export function createNewExecutedEvent( newExecutedEvent.parameters.push(actorParam); newExecutedEvent.parameters.push(callIdParam); newExecutedEvent.parameters.push(actionsParam); + + if (allowFailureMapParam) { + newExecutedEvent.parameters.push(allowFailureMapParam); + } + newExecutedEvent.parameters.push(failureMapParam); newExecutedEvent.parameters.push(execResultsParams); @@ -494,3 +508,25 @@ export function createDaoEntityState( return daoEntity; } + +export function encodeWithFunctionSelector( + tuple: Array, + funcSelector: string, + isDynamic: boolean = false +): Bytes { + // ethereum.decode inside subgraph doesn't append 0x00...20 while the actual event + // thrown from the real network includes this appended offset. Due to this, mappings contain + // extra logic(appending the offset to the actual calldata in order to do ethereum.decode). + // Due to this, from the tests, we need to append it as well. Note that this rule only applies + // when the emitted event contains at least 1 dynamic type. + let index = isDynamic == true ? 66 : 2; + + let calldata = ethereum + .encode(ethereum.Value.fromTuple(changetype(tuple)))! + .toHexString() + .substring(index); + + let functionData = funcSelector.concat(calldata); + + return Bytes.fromHexString(functionData); +} diff --git a/packages/subgraph/tests/token/utils.ts b/packages/subgraph/tests/token/utils.ts index 2170f5bd8..92a41f715 100644 --- a/packages/subgraph/tests/token/utils.ts +++ b/packages/subgraph/tests/token/utils.ts @@ -24,7 +24,7 @@ import { CREATED_AT, ALLOW_FAILURE_MAP } from '../constants'; -import {Transfer as ERC20TransferEvent} from '../../generated/templates/DaoTemplate/ERC20'; +import {Transfer as ERC20TransferEvent} from '../../generated/templates/TokenVoting/ERC20'; // events diff --git a/packages/subgraph/tests/utils.ts b/packages/subgraph/tests/utils.ts index f6daa0d7c..6e3d82695 100644 --- a/packages/subgraph/tests/utils.ts +++ b/packages/subgraph/tests/utils.ts @@ -4,13 +4,13 @@ import {createMockedFunction} from 'matchstick-as/assembly/index'; export function createMockGetter( contractAddress: string, funcName: string, - funcSigniture: string, + funcSignature: string, returns: ethereum.Value[] ): void { createMockedFunction( Address.fromString(contractAddress), funcName, - funcSigniture + funcSignature ) .withArgs([]) .returns(returns);