From ec174bbbda57336a8e98fa2f76c6b324fa67cc68 Mon Sep 17 00:00:00 2001 From: Rinat Date: Mon, 25 Nov 2024 09:44:57 +0100 Subject: [PATCH 1/8] Fix final approval UI UX (#92) --- packages/hardhat/contracts/Stream.sol | 102 +- packages/hardhat/deployments/sepolia/.chainId | 1 + .../hardhat/deployments/sepolia/Stream.json | 1046 +++++++++++++++++ .../66949c7747c59450b1528b6c03e97e3b.json | 56 + .../_components/ApprovalVoteModal/index.tsx | 4 +- .../_components/FinalApproveModal/index.tsx | 111 +- .../_components/FinalApproveModal/schema.tsx | 1 - .../nextjs/app/admin/_components/Proposal.tsx | 6 +- .../app/api/stages/revalidate-status/route.ts | 1 - .../pg-ens/form-fields/FormInput.tsx | 8 +- .../nextjs/contracts/deployedContracts.ts | 794 ++++++++++++- packages/nextjs/scaffold.config.ts | 4 +- packages/ponder/ponder.config.ts | 48 +- packages/ponder/src/StreamContract.ts | 6 +- 14 files changed, 2070 insertions(+), 118 deletions(-) create mode 100644 packages/hardhat/deployments/sepolia/.chainId create mode 100644 packages/hardhat/deployments/sepolia/Stream.json create mode 100644 packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json diff --git a/packages/hardhat/contracts/Stream.sol b/packages/hardhat/contracts/Stream.sol index 4f1f0ff..59f0a26 100644 --- a/packages/hardhat/contracts/Stream.sol +++ b/packages/hardhat/contracts/Stream.sol @@ -33,6 +33,11 @@ contract Stream is AccessControl { uint8 stageNumber ); event AddGrant(uint256 indexed grantId, address indexed to, uint256 amount); + event ReinitializeGrant( + uint256 indexed grantId, + address indexed to, + uint256 amount + ); event MoveGrantToNextStage( uint256 indexed grantId, address indexed to, @@ -40,6 +45,13 @@ contract Stream is AccessControl { uint8 grantNumber, uint8 stageNumber ); + event ReinitializeNextStage( + uint256 indexed grantId, + address indexed builder, + uint256 amount, + uint8 grantNumber, + uint8 stageNumber + ); event UpdateGrant( uint256 indexed grantId, address indexed to, @@ -59,6 +71,7 @@ contract Stream is AccessControl { error InsufficientStreamFunds(); error FailedToSendEther(); error PreviousAmountNotFullyWithdrawn(); + error AlreadyWithdrawnFromGrant(); constructor(address[] memory _initialOwners) { _setRoleAdmin(OWNER_ROLE, OWNER_ROLE); @@ -92,7 +105,27 @@ contract Stream is AccessControl { uint256 _cap, uint8 _grantNumber ) public onlyRole(OWNER_ROLE) returns (uint256) { - uint256 grantId = nextGrantId++; + // check if grantStream with same grantNumber already exists + uint256 existingGrantId; + uint256[] memory existingBuilderGrants = builderGrants[_builder]; + for (uint i = 0; i < existingBuilderGrants.length; i++) { + GrantStream memory existingGrant = grantStreams[ + existingBuilderGrants[i] + ]; + if (existingGrant.grantNumber == _grantNumber) { + if (existingGrant.cap != existingGrant.amountLeft) { + revert AlreadyWithdrawnFromGrant(); + } + existingGrantId = existingBuilderGrants[i]; + break; + } + } + + // update existing grant or create new one + uint256 grantId = existingGrantId != 0 + ? existingGrantId + : nextGrantId++; + grantStreams[grantId] = GrantStream({ cap: _cap, last: block.timestamp, @@ -101,8 +134,14 @@ contract Stream is AccessControl { stageNumber: 1, builder: _builder }); - builderGrants[_builder].push(grantId); - emit AddGrant(grantId, _builder, _cap); + + if (existingGrantId == 0) { + builderGrants[_builder].push(grantId); + emit AddGrant(grantId, _builder, _cap); + } else { + emit ReinitializeGrant(grantId, _builder, _cap); + } + return grantId; } @@ -113,28 +152,43 @@ contract Stream is AccessControl { GrantStream storage grantStream = grantStreams[_grantId]; if (grantStream.cap == 0) revert NoActiveStream(); - if (grantStream.amountLeft > DUST_THRESHOLD) - revert PreviousAmountNotFullyWithdrawn(); - - if (grantStream.amountLeft > 0) { - (bool sent, ) = payable(grantStream.builder).call{ - value: grantStream.amountLeft - }(""); - if (!sent) revert FailedToSendEther(); + // If amountLeft equals cap, reinitialize with same stage number + if (grantStream.amountLeft == grantStream.cap) { + grantStream.cap = _cap; + grantStream.last = block.timestamp; + grantStream.amountLeft = _cap; + // Stage number remains the same + emit ReinitializeNextStage( + _grantId, + grantStream.builder, + _cap, + grantStream.grantNumber, + grantStream.stageNumber + ); + } else { + if (grantStream.amountLeft > DUST_THRESHOLD) + revert PreviousAmountNotFullyWithdrawn(); + + if (grantStream.amountLeft > 0) { + (bool sent, ) = payable(grantStream.builder).call{ + value: grantStream.amountLeft + }(""); + if (!sent) revert FailedToSendEther(); + } + + grantStream.cap = _cap; + grantStream.last = block.timestamp; + grantStream.amountLeft = _cap; + grantStream.stageNumber += 1; + + emit MoveGrantToNextStage( + _grantId, + grantStream.builder, + _cap, + grantStream.grantNumber, + grantStream.stageNumber + ); } - - grantStream.cap = _cap; - grantStream.last = block.timestamp; - grantStream.amountLeft = _cap; - grantStream.stageNumber += 1; - - emit MoveGrantToNextStage( - _grantId, - grantStream.builder, - _cap, - grantStream.grantNumber, - grantStream.stageNumber - ); } function updateGrant( diff --git a/packages/hardhat/deployments/sepolia/.chainId b/packages/hardhat/deployments/sepolia/.chainId new file mode 100644 index 0000000..bd8d1cd --- /dev/null +++ b/packages/hardhat/deployments/sepolia/.chainId @@ -0,0 +1 @@ +11155111 \ No newline at end of file diff --git a/packages/hardhat/deployments/sepolia/Stream.json b/packages/hardhat/deployments/sepolia/Stream.json new file mode 100644 index 0000000..fb578a6 --- /dev/null +++ b/packages/hardhat/deployments/sepolia/Stream.json @@ -0,0 +1,1046 @@ +{ + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "abi": [ + { + "inputs": [ + { + "internalType": "address[]", + "name": "_initialOwners", + "type": "address[]" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "FailedToSendEther", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientContractFunds", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientStreamFunds", + "type": "error" + }, + { + "inputs": [], + "name": "NoActiveStream", + "type": "error" + }, + { + "inputs": [], + "name": "PreviousAmountNotFullyWithdrawn", + "type": "error" + }, + { + "inputs": [], + "name": "UnauthorizedWithdrawal", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AddGrant", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "addedBy", + "type": "address" + } + ], + "name": "AddOwner", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "stageNumber", + "type": "uint8" + } + ], + "name": "MoveGrantToNextStage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "removedOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "removedBy", + "type": "address" + } + ], + "name": "RemoveOwner", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cap", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "last", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLeft", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "stageNumber", + "type": "uint8" + } + ], + "name": "UpdateGrant", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "stageNumber", + "type": "uint8" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DUST_THRESHOLD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FULL_STREAM_UNLOCK_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OWNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_builder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_cap", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "_grantNumber", + "type": "uint8" + } + ], + "name": "addGrantStream", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "addOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "builderGrants", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_builder", + "type": "address" + } + ], + "name": "getBuilderGrantCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantStreams", + "outputs": [ + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "last", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountLeft", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "stageNumber", + "type": "uint8" + }, + { + "internalType": "address", + "name": "builder", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_grantId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_cap", + "type": "uint256" + } + ], + "name": "moveGrantToNextStage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "nextGrantId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "removeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_grantId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_reason", + "type": "string" + } + ], + "name": "streamWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_grantId", + "type": "uint256" + } + ], + "name": "unlockedGrantAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_grantId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_cap", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_last", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amountLeft", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "_stageNumber", + "type": "uint8" + } + ], + "name": "updateGrant", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "receipt": { + "to": null, + "from": "0x55b9CB0bCf56057010b9c471e7D42d60e1111EEa", + "contractAddress": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "transactionIndex": 31, + "gasUsed": "1389401", + "logsBloom": "0x0000000400000000080000000000000008008000000000000002000000000000000000000000000000000100000000000000000000000000000000000050000040000000000000000000000000100000000000000000000000000000000000000000000002000c400000020000000800000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000001000000000000020000000000000000000000000000000000000000000000100000000000020000000001000000000000000000000001000000000000000000000000008002000", + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f", + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "logs": [ + { + "transactionIndex": 31, + "blockNumber": 6641664, + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "topics": [ + "0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e" + ], + "data": "0x", + "logIndex": 64, + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" + }, + { + "transactionIndex": 31, + "blockNumber": 6641664, + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea", + "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" + ], + "data": "0x", + "logIndex": 65, + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" + }, + { + "transactionIndex": 31, + "blockNumber": 6641664, + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "0x00000000000000000000000060583563d5879c2e59973e5718c7de2147971807", + "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" + ], + "data": "0x", + "logIndex": 66, + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" + }, + { + "transactionIndex": 31, + "blockNumber": 6641664, + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "0x000000000000000000000000b8224dfcf3c174331a8e6a841aeea7df321f6d8e", + "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" + ], + "data": "0x", + "logIndex": 67, + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" + }, + { + "transactionIndex": 31, + "blockNumber": 6641664, + "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", + "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "0x000000000000000000000000b4f53bd85c00ef22946d24ae26bc38ac64f5e7b1", + "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" + ], + "data": "0x", + "logIndex": 68, + "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" + } + ], + "blockNumber": 6641664, + "cumulativeGasUsed": "6982808", + "status": 1, + "byzantium": true + }, + "args": [ + [ + "0x55b9CB0bCf56057010b9c471e7D42d60e1111EEa", + "0x60583563D5879C2E59973E5718c7DE2147971807", + "0xb8224dfCf3C174331a8e6a841AEEa7dF321f6D8E", + "0xB4F53bd85c00EF22946d24Ae26BC38Ac64F5E7B1" + ] + ], + "numDeployments": 1, + "solcInputHash": "66949c7747c59450b1528b6c03e97e3b", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_initialOwners\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientContractFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientStreamFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoActiveStream\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PreviousAmountNotFullyWithdrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AddGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addedBy\",\"type\":\"address\"}],\"name\":\"AddOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"MoveGrantToNextStage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedBy\",\"type\":\"address\"}],\"name\":\"RemoveOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"UpdateGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DUST_THRESHOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_STREAM_UNLOCK_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OWNER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_grantNumber\",\"type\":\"uint8\"}],\"name\":\"addGrantStream\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"addOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"builderGrants\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"}],\"name\":\"getBuilderGrantCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantStreams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"}],\"name\":\"moveGrantToNextStage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextGrantId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"removeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"streamWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"}],\"name\":\"unlockedGrantAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_stageNumber\",\"type\":\"uint8\"}],\"name\":\"updateGrant\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Stream.sol\":\"Stream\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => RoleData) private _roles;\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\\n * Overriding this function changes the behavior of the {onlyRole} modifier.\\n *\\n * Format of the revert message is described in {_checkRole}.\\n *\\n * _Available since v4.6._\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(account),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\\n return _roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * May emit a {RoleGranted} event.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n _roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67e3daf189111d6d5b0464ed09cf9f0605a22c4b965a7fcecd707101faff008a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/Stream.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\n\\ncontract Stream is AccessControl {\\n\\tbytes32 public constant OWNER_ROLE = keccak256(\\\"OWNER_ROLE\\\");\\n\\n\\tstruct GrantStream {\\n\\t\\tuint256 cap;\\n\\t\\tuint256 last;\\n\\t\\tuint256 amountLeft;\\n\\t\\tuint8 grantNumber;\\n\\t\\tuint8 stageNumber;\\n\\t\\taddress builder;\\n\\t}\\n\\n\\tmapping(uint256 => GrantStream) public grantStreams;\\n\\tuint256 public nextGrantId = 1;\\n\\n\\tmapping(address => uint256[]) public builderGrants;\\n\\n\\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 30 days\\n\\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\\n\\n\\tevent Withdraw(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tstring reason,\\n\\t\\tuint256 grantId,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\\n\\tevent MoveGrantToNextStage(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent UpdateGrant(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 cap,\\n\\t\\tuint256 last,\\n\\t\\tuint256 amountLeft,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddOwner(address indexed newOwner, address indexed addedBy);\\n\\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\\n\\n\\t// Custom errors\\n\\terror NoActiveStream();\\n\\terror InsufficientContractFunds();\\n\\terror UnauthorizedWithdrawal();\\n\\terror InsufficientStreamFunds();\\n\\terror FailedToSendEther();\\n\\terror PreviousAmountNotFullyWithdrawn();\\n\\n\\tconstructor(address[] memory _initialOwners) {\\n\\t\\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\\n\\t\\tfor (uint i = 0; i < _initialOwners.length; i++) {\\n\\t\\t\\t_grantRole(OWNER_ROLE, _initialOwners[i]);\\n\\t\\t}\\n\\t}\\n\\n\\tfunction unlockedGrantAmount(\\n\\t\\tuint256 _grantId\\n\\t) public view returns (uint256) {\\n\\t\\tGrantStream memory grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft == 0) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\\n\\t\\t\\tFULL_STREAM_UNLOCK_PERIOD;\\n\\n\\t\\treturn\\n\\t\\t\\tunlockedAmount > grantStream.amountLeft\\n\\t\\t\\t\\t? grantStream.amountLeft\\n\\t\\t\\t\\t: unlockedAmount;\\n\\t}\\n\\n\\tfunction addGrantStream(\\n\\t\\taddress _builder,\\n\\t\\tuint256 _cap,\\n\\t\\tuint8 _grantNumber\\n\\t) public onlyRole(OWNER_ROLE) returns (uint256) {\\n\\t\\tuint256 grantId = nextGrantId++;\\n\\t\\tgrantStreams[grantId] = GrantStream({\\n\\t\\t\\tcap: _cap,\\n\\t\\t\\tlast: block.timestamp,\\n\\t\\t\\tamountLeft: _cap,\\n\\t\\t\\tgrantNumber: _grantNumber,\\n\\t\\t\\tstageNumber: 1,\\n\\t\\t\\tbuilder: _builder\\n\\t\\t});\\n\\t\\tbuilderGrants[_builder].push(grantId);\\n\\t\\temit AddGrant(grantId, _builder, _cap);\\n\\t\\treturn grantId;\\n\\t}\\n\\n\\tfunction moveGrantToNextStage(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft > DUST_THRESHOLD)\\n\\t\\t\\trevert PreviousAmountNotFullyWithdrawn();\\n\\n\\t\\tif (grantStream.amountLeft > 0) {\\n\\t\\t\\t(bool sent, ) = payable(grantStream.builder).call{\\n\\t\\t\\t\\tvalue: grantStream.amountLeft\\n\\t\\t\\t}(\\\"\\\");\\n\\t\\t\\tif (!sent) revert FailedToSendEther();\\n\\t\\t}\\n\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = block.timestamp;\\n\\t\\tgrantStream.amountLeft = _cap;\\n\\t\\tgrantStream.stageNumber += 1;\\n\\n\\t\\temit MoveGrantToNextStage(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction updateGrant(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap,\\n\\t\\tuint256 _last,\\n\\t\\tuint256 _amountLeft,\\n\\t\\tuint8 _stageNumber\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = _last;\\n\\t\\tgrantStream.amountLeft = _amountLeft;\\n\\t\\tgrantStream.stageNumber = _stageNumber;\\n\\n\\t\\temit UpdateGrant(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.last,\\n\\t\\t\\tgrantStream.amountLeft,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction streamWithdraw(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _amount,\\n\\t\\tstring memory _reason\\n\\t) public {\\n\\t\\tif (address(this).balance < _amount) revert InsufficientContractFunds();\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\\n\\n\\t\\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\\n\\t\\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\\n\\n\\t\\tgrantStream.last = grantStream.last + timeToDeduct;\\n\\t\\tgrantStream.amountLeft -= _amount;\\n\\n\\t\\t(bool sent, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n\\t\\tif (!sent) revert FailedToSendEther();\\n\\n\\t\\temit Withdraw(\\n\\t\\t\\tmsg.sender,\\n\\t\\t\\t_amount,\\n\\t\\t\\t_reason,\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction getBuilderGrantCount(\\n\\t\\taddress _builder\\n\\t) public view returns (uint256) {\\n\\t\\treturn builderGrants[_builder].length;\\n\\t}\\n\\n\\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\\n\\t\\tgrantRole(OWNER_ROLE, newOwner);\\n\\t\\temit AddOwner(newOwner, msg.sender);\\n\\t}\\n\\n\\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\\n\\t\\trevokeRole(OWNER_ROLE, owner);\\n\\t\\temit RemoveOwner(owner, msg.sender);\\n\\t}\\n\\n\\treceive() external payable {}\\n\\n\\tfallback() external payable {}\\n}\\n\",\"keccak256\":\"0xf5915a4a9feb7db4b58cdd9de70ceab466c11d75769d2596452336c6f75b62ce\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405260016002553480156200001657600080fd5b5060405162001863380380620018638339810160408190526200003991620001da565b620000546000805160206200184383398151915280620000bb565b60005b8151811015620000b3576200009e600080516020620018438339815191528383815181106200008a576200008a620002ac565b60200260200101516200010660201b60201c565b80620000aa81620002c2565b91505062000057565b5050620002ea565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001a3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620001d557600080fd5b919050565b60006020808385031215620001ee57600080fd5b82516001600160401b03808211156200020657600080fd5b818501915085601f8301126200021b57600080fd5b815181811115620002305762000230620001a7565b8060051b604051601f19603f83011681018181108582111715620002585762000258620001a7565b6040529182528482019250838101850191888311156200027757600080fd5b938501935b82851015620002a0576200029085620001bd565b845293850193928501926200027c565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620002e357634e487b7160e01b600052601160045260246000fd5b5060010190565b61154980620002fa6000396000f3fe6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea914610328578063d547741f1461033e578063dd7dc9a91461035e578063e58378bb14610379578063ed2c9d091461039b578063f1f693d11461043857005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110ab565b61046e565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f1565b6104a5565b34801561018c57600080fd5b506101b061019b36600461110c565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611125565b61050f565b3480156101ea57600080fd5b506101296101f9366004611125565b610539565b34801561020a57600080fd5b50610129610219366004611151565b6105bc565b34801561022a57600080fd5b506101b0610239366004611184565b61076c565b34801561024a57600080fd5b506101296102593660046111d6565b610916565b34801561026a57600080fd5b506101296102793660046110f1565b610ae9565b34801561028a57600080fd5b506101b061029936600461110c565b610b53565b3480156102aa57600080fd5b506101296102b936600461129a565b610c3e565b3480156102ca57600080fd5b5061014b6102d9366004611125565b610d28565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e3565b610d51565b34801561031f57600080fd5b506101b060b481565b34801561033457600080fd5b506101b060025481565b34801561034a57600080fd5b50610129610359366004611125565b610d82565b34801561036a57600080fd5b506101b066038d7ea4c6800081565b34801561038557600080fd5b506101b06000805160206114f483398151915281565b3480156103a757600080fd5b506103fc6103b636600461110c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044457600080fd5b506101b06104533660046110f1565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b148061049f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f48339815191526104bd81610da7565b6104d56000805160206114f483398151915283610d82565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052a81610da7565b6105348383610db4565b505050565b6001600160a01b03811633146105ae5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105b88282610e38565b5050565b6000805160206114f48339815191526105d481610da7565b6000838152600160205260408120805490910361060457604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106305760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106bc57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610693576040519150601f19603f3d011682016040523d82523d6000602084013e610698565b606091505b50509050806106ba57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106eb908290610100900460ff16611323565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f483398151915261078681610da7565b60028054600091826107978361133c565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090591815260200190565b60405180910390a395945050505050565b814710156109375760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099a576040516360b39bc560e01b815260040160405180910390fd5b60006109a585610b53565b9050838110156109c85760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109da9190611355565b90506000826109e98784611368565b6109f3919061137f565b9050808460010154610a0591906113a1565b846001018190555085846002016000828254610a219190611355565b9091555050604051600090339088908381818185875af1925050503d8060008114610a68576040519150601f19603f3d011682016040523d82523d6000602084013e610a6d565b606091505b5050905080610a8f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad7918b918b918e9160ff8083169261010090041690611404565b60405180910390a25050505050505050565b6000805160206114f4833981519152610b0181610da7565b610b196000805160206114f48339815191528361050f565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bea5750600092915050565b6000816020015142610bfc9190611355565b9050600060b4828460000151610c129190611368565b610c1c919061137f565b905082604001518111610c2f5780610c35565b82604001515b95945050505050565b6000805160206114f4833981519152610c5681610da7565b60008681526001602052604081208054909103610c8657604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d6d57600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610d9d81610da7565b6105348383610e38565b610db18133610e9d565b50565b610dbe8282610d28565b6105b8576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e428282610d28565b156105b8576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610ea78282610d28565b6105b857610eb481610ef6565b610ebf836020610f08565b604051602001610ed092919061143e565b60408051601f198184030181529082905262461bcd60e51b82526105a5916004016114b3565b606061049f6001600160a01b03831660145b60606000610f17836002611368565b610f229060026113a1565b67ffffffffffffffff811115610f3a57610f3a6111c0565b6040519080825280601f01601f191660200182016040528015610f64576020820181803683370190505b509050600360fc1b81600081518110610f7f57610f7f6114c6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fae57610fae6114c6565b60200101906001600160f81b031916908160001a9053506000610fd2846002611368565b610fdd9060016113a1565b90505b6001811115611055576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611011576110116114c6565b1a60f81b828281518110611027576110276114c6565b60200101906001600160f81b031916908160001a90535060049490941c9361104e816114dc565b9050610fe0565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a5565b9392505050565b6000602082840312156110bd57600080fd5b81356001600160e01b0319811681146110a457600080fd5b80356001600160a01b03811681146110ec57600080fd5b919050565b60006020828403121561110357600080fd5b6110a4826110d5565b60006020828403121561111e57600080fd5b5035919050565b6000806040838503121561113857600080fd5b82359150611148602084016110d5565b90509250929050565b6000806040838503121561116457600080fd5b50508035926020909101359150565b803560ff811681146110ec57600080fd5b60008060006060848603121561119957600080fd5b6111a2846110d5565b9250602084013591506111b760408501611173565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111eb57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121157600080fd5b818601915086601f83011261122557600080fd5b813581811115611237576112376111c0565b604051601f8201601f19908116603f0116810190838211818310171561125f5761125f6111c0565b8160405282815289602084870101111561127857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b257600080fd5b853594506020860135935060408601359250606086013591506112d760808701611173565b90509295509295909350565b600080604083850312156112f657600080fd5b6112ff836110d5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111561049f5761049f61130d565b60006001820161134e5761134e61130d565b5060010190565b8181038181111561049f5761049f61130d565b808202811582820484141761049f5761049f61130d565b60008261139c57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561049f5761049f61130d565b60005b838110156113cf5781810151838201526020016113b7565b50506000910152565b600081518084526113f08160208601602086016113b4565b601f01601f19169290920160200192915050565b85815260a06020820152600061141d60a08301876113d8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516114768160178501602088016113b4565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114a78160288401602088016113b4565b01602801949350505050565b6020815260006110a460208301846113d8565b634e487b7160e01b600052603260045260246000fd5b6000816114eb576114eb61130d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220ff6e1722a4db24900b0b16bf92418a2f66f8054b2e46c6f8d1b867836d7aa23b64736f6c63430008110033b19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "deployedBytecode": "0x6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea914610328578063d547741f1461033e578063dd7dc9a91461035e578063e58378bb14610379578063ed2c9d091461039b578063f1f693d11461043857005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110ab565b61046e565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f1565b6104a5565b34801561018c57600080fd5b506101b061019b36600461110c565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611125565b61050f565b3480156101ea57600080fd5b506101296101f9366004611125565b610539565b34801561020a57600080fd5b50610129610219366004611151565b6105bc565b34801561022a57600080fd5b506101b0610239366004611184565b61076c565b34801561024a57600080fd5b506101296102593660046111d6565b610916565b34801561026a57600080fd5b506101296102793660046110f1565b610ae9565b34801561028a57600080fd5b506101b061029936600461110c565b610b53565b3480156102aa57600080fd5b506101296102b936600461129a565b610c3e565b3480156102ca57600080fd5b5061014b6102d9366004611125565b610d28565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e3565b610d51565b34801561031f57600080fd5b506101b060b481565b34801561033457600080fd5b506101b060025481565b34801561034a57600080fd5b50610129610359366004611125565b610d82565b34801561036a57600080fd5b506101b066038d7ea4c6800081565b34801561038557600080fd5b506101b06000805160206114f483398151915281565b3480156103a757600080fd5b506103fc6103b636600461110c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044457600080fd5b506101b06104533660046110f1565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b148061049f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f48339815191526104bd81610da7565b6104d56000805160206114f483398151915283610d82565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052a81610da7565b6105348383610db4565b505050565b6001600160a01b03811633146105ae5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105b88282610e38565b5050565b6000805160206114f48339815191526105d481610da7565b6000838152600160205260408120805490910361060457604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106305760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106bc57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610693576040519150601f19603f3d011682016040523d82523d6000602084013e610698565b606091505b50509050806106ba57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106eb908290610100900460ff16611323565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f483398151915261078681610da7565b60028054600091826107978361133c565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090591815260200190565b60405180910390a395945050505050565b814710156109375760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099a576040516360b39bc560e01b815260040160405180910390fd5b60006109a585610b53565b9050838110156109c85760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109da9190611355565b90506000826109e98784611368565b6109f3919061137f565b9050808460010154610a0591906113a1565b846001018190555085846002016000828254610a219190611355565b9091555050604051600090339088908381818185875af1925050503d8060008114610a68576040519150601f19603f3d011682016040523d82523d6000602084013e610a6d565b606091505b5050905080610a8f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad7918b918b918e9160ff8083169261010090041690611404565b60405180910390a25050505050505050565b6000805160206114f4833981519152610b0181610da7565b610b196000805160206114f48339815191528361050f565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bea5750600092915050565b6000816020015142610bfc9190611355565b9050600060b4828460000151610c129190611368565b610c1c919061137f565b905082604001518111610c2f5780610c35565b82604001515b95945050505050565b6000805160206114f4833981519152610c5681610da7565b60008681526001602052604081208054909103610c8657604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d6d57600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610d9d81610da7565b6105348383610e38565b610db18133610e9d565b50565b610dbe8282610d28565b6105b8576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e428282610d28565b156105b8576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610ea78282610d28565b6105b857610eb481610ef6565b610ebf836020610f08565b604051602001610ed092919061143e565b60408051601f198184030181529082905262461bcd60e51b82526105a5916004016114b3565b606061049f6001600160a01b03831660145b60606000610f17836002611368565b610f229060026113a1565b67ffffffffffffffff811115610f3a57610f3a6111c0565b6040519080825280601f01601f191660200182016040528015610f64576020820181803683370190505b509050600360fc1b81600081518110610f7f57610f7f6114c6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fae57610fae6114c6565b60200101906001600160f81b031916908160001a9053506000610fd2846002611368565b610fdd9060016113a1565b90505b6001811115611055576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611011576110116114c6565b1a60f81b828281518110611027576110276114c6565b60200101906001600160f81b031916908160001a90535060049490941c9361104e816114dc565b9050610fe0565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a5565b9392505050565b6000602082840312156110bd57600080fd5b81356001600160e01b0319811681146110a457600080fd5b80356001600160a01b03811681146110ec57600080fd5b919050565b60006020828403121561110357600080fd5b6110a4826110d5565b60006020828403121561111e57600080fd5b5035919050565b6000806040838503121561113857600080fd5b82359150611148602084016110d5565b90509250929050565b6000806040838503121561116457600080fd5b50508035926020909101359150565b803560ff811681146110ec57600080fd5b60008060006060848603121561119957600080fd5b6111a2846110d5565b9250602084013591506111b760408501611173565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111eb57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121157600080fd5b818601915086601f83011261122557600080fd5b813581811115611237576112376111c0565b604051601f8201601f19908116603f0116810190838211818310171561125f5761125f6111c0565b8160405282815289602084870101111561127857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b257600080fd5b853594506020860135935060408601359250606086013591506112d760808701611173565b90509295509295909350565b600080604083850312156112f657600080fd5b6112ff836110d5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111561049f5761049f61130d565b60006001820161134e5761134e61130d565b5060010190565b8181038181111561049f5761049f61130d565b808202811582820484141761049f5761049f61130d565b60008261139c57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561049f5761049f61130d565b60005b838110156113cf5781810151838201526020016113b7565b50506000910152565b600081518084526113f08160208601602086016113b4565b601f01601f19169290920160200192915050565b85815260a06020820152600061141d60a08301876113d8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516114768160178501602088016113b4565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114a78160288401602088016113b4565b01602801949350505050565b6020815260006110a460208301846113d8565b634e487b7160e01b600052603260045260246000fd5b6000816114eb576114eb61130d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220ff6e1722a4db24900b0b16bf92418a2f66f8054b2e46c6f8d1b867836d7aa23b64736f6c63430008110033", + "devdoc": { + "kind": "dev", + "methods": { + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "renounceRole(bytes32,address)": { + "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event." + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event." + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 24, + "contract": "contracts/Stream.sol:Stream", + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)19_storage)" + }, + { + "astId": 1514, + "contract": "contracts/Stream.sol:Stream", + "label": "grantStreams", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_struct(GrantStream)1509_storage)" + }, + { + "astId": 1517, + "contract": "contracts/Stream.sol:Stream", + "label": "nextGrantId", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 1522, + "contract": "contracts/Stream.sol:Stream", + "label": "builderGrants", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_array(t_uint256)dyn_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)dyn_storage": { + "base": "t_uint256", + "encoding": "dynamic_array", + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_array(t_uint256)dyn_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256[])", + "numberOfBytes": "32", + "value": "t_array(t_uint256)dyn_storage" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_bytes32,t_struct(RoleData)19_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32", + "value": "t_struct(RoleData)19_storage" + }, + "t_mapping(t_uint256,t_struct(GrantStream)1509_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct Stream.GrantStream)", + "numberOfBytes": "32", + "value": "t_struct(GrantStream)1509_storage" + }, + "t_struct(GrantStream)1509_storage": { + "encoding": "inplace", + "label": "struct Stream.GrantStream", + "members": [ + { + "astId": 1498, + "contract": "contracts/Stream.sol:Stream", + "label": "cap", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 1500, + "contract": "contracts/Stream.sol:Stream", + "label": "last", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 1502, + "contract": "contracts/Stream.sol:Stream", + "label": "amountLeft", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 1504, + "contract": "contracts/Stream.sol:Stream", + "label": "grantNumber", + "offset": 0, + "slot": "3", + "type": "t_uint8" + }, + { + "astId": 1506, + "contract": "contracts/Stream.sol:Stream", + "label": "stageNumber", + "offset": 1, + "slot": "3", + "type": "t_uint8" + }, + { + "astId": 1508, + "contract": "contracts/Stream.sol:Stream", + "label": "builder", + "offset": 2, + "slot": "3", + "type": "t_address" + } + ], + "numberOfBytes": "128" + }, + "t_struct(RoleData)19_storage": { + "encoding": "inplace", + "label": "struct AccessControl.RoleData", + "members": [ + { + "astId": 16, + "contract": "contracts/Stream.sol:Stream", + "label": "members", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 18, + "contract": "contracts/Stream.sol:Stream", + "label": "adminRole", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json b/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json new file mode 100644 index 0000000..fadf364 --- /dev/null +++ b/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json @@ -0,0 +1,56 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "contracts/Stream.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ncontract Stream is AccessControl {\n\tbytes32 public constant OWNER_ROLE = keccak256(\"OWNER_ROLE\");\n\n\tstruct GrantStream {\n\t\tuint256 cap;\n\t\tuint256 last;\n\t\tuint256 amountLeft;\n\t\tuint8 grantNumber;\n\t\tuint8 stageNumber;\n\t\taddress builder;\n\t}\n\n\tmapping(uint256 => GrantStream) public grantStreams;\n\tuint256 public nextGrantId = 1;\n\n\tmapping(address => uint256[]) public builderGrants;\n\n\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 30 days\n\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\n\n\tevent Withdraw(\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tstring reason,\n\t\tuint256 grantId,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\n\tevent MoveGrantToNextStage(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent UpdateGrant(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 cap,\n\t\tuint256 last,\n\t\tuint256 amountLeft,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddOwner(address indexed newOwner, address indexed addedBy);\n\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\n\n\t// Custom errors\n\terror NoActiveStream();\n\terror InsufficientContractFunds();\n\terror UnauthorizedWithdrawal();\n\terror InsufficientStreamFunds();\n\terror FailedToSendEther();\n\terror PreviousAmountNotFullyWithdrawn();\n\n\tconstructor(address[] memory _initialOwners) {\n\t\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\n\t\tfor (uint i = 0; i < _initialOwners.length; i++) {\n\t\t\t_grantRole(OWNER_ROLE, _initialOwners[i]);\n\t\t}\n\t}\n\n\tfunction unlockedGrantAmount(\n\t\tuint256 _grantId\n\t) public view returns (uint256) {\n\t\tGrantStream memory grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft == 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\n\t\t\tFULL_STREAM_UNLOCK_PERIOD;\n\n\t\treturn\n\t\t\tunlockedAmount > grantStream.amountLeft\n\t\t\t\t? grantStream.amountLeft\n\t\t\t\t: unlockedAmount;\n\t}\n\n\tfunction addGrantStream(\n\t\taddress _builder,\n\t\tuint256 _cap,\n\t\tuint8 _grantNumber\n\t) public onlyRole(OWNER_ROLE) returns (uint256) {\n\t\tuint256 grantId = nextGrantId++;\n\t\tgrantStreams[grantId] = GrantStream({\n\t\t\tcap: _cap,\n\t\t\tlast: block.timestamp,\n\t\t\tamountLeft: _cap,\n\t\t\tgrantNumber: _grantNumber,\n\t\t\tstageNumber: 1,\n\t\t\tbuilder: _builder\n\t\t});\n\t\tbuilderGrants[_builder].push(grantId);\n\t\temit AddGrant(grantId, _builder, _cap);\n\t\treturn grantId;\n\t}\n\n\tfunction moveGrantToNextStage(\n\t\tuint256 _grantId,\n\t\tuint256 _cap\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft > DUST_THRESHOLD)\n\t\t\trevert PreviousAmountNotFullyWithdrawn();\n\n\t\tif (grantStream.amountLeft > 0) {\n\t\t\t(bool sent, ) = payable(grantStream.builder).call{\n\t\t\t\tvalue: grantStream.amountLeft\n\t\t\t}(\"\");\n\t\t\tif (!sent) revert FailedToSendEther();\n\t\t}\n\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = block.timestamp;\n\t\tgrantStream.amountLeft = _cap;\n\t\tgrantStream.stageNumber += 1;\n\n\t\temit MoveGrantToNextStage(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction updateGrant(\n\t\tuint256 _grantId,\n\t\tuint256 _cap,\n\t\tuint256 _last,\n\t\tuint256 _amountLeft,\n\t\tuint8 _stageNumber\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = _last;\n\t\tgrantStream.amountLeft = _amountLeft;\n\t\tgrantStream.stageNumber = _stageNumber;\n\n\t\temit UpdateGrant(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.last,\n\t\t\tgrantStream.amountLeft,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction streamWithdraw(\n\t\tuint256 _grantId,\n\t\tuint256 _amount,\n\t\tstring memory _reason\n\t) public {\n\t\tif (address(this).balance < _amount) revert InsufficientContractFunds();\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\n\n\t\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\n\t\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\n\n\t\tgrantStream.last = grantStream.last + timeToDeduct;\n\t\tgrantStream.amountLeft -= _amount;\n\n\t\t(bool sent, ) = msg.sender.call{ value: _amount }(\"\");\n\t\tif (!sent) revert FailedToSendEther();\n\n\t\temit Withdraw(\n\t\t\tmsg.sender,\n\t\t\t_amount,\n\t\t\t_reason,\n\t\t\t_grantId,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction getBuilderGrantCount(\n\t\taddress _builder\n\t) public view returns (uint256) {\n\t\treturn builderGrants[_builder].length;\n\t}\n\n\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\n\t\tgrantRole(OWNER_ROLE, newOwner);\n\t\temit AddOwner(newOwner, msg.sender);\n\t}\n\n\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\n\t\trevokeRole(OWNER_ROLE, owner);\n\t\temit RemoveOwner(owner, msg.sender);\n\t}\n\n\treceive() external payable {}\n\n\tfallback() external payable {}\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/nextjs/app/admin/_components/ApprovalVoteModal/index.tsx b/packages/nextjs/app/admin/_components/ApprovalVoteModal/index.tsx index 90bd76c..4c5ce6e 100644 --- a/packages/nextjs/app/admin/_components/ApprovalVoteModal/index.tsx +++ b/packages/nextjs/app/admin/_components/ApprovalVoteModal/index.tsx @@ -81,9 +81,7 @@ export const ApprovalVoteModal = forwardRef {(isPostingApprovalVote || isSigning) && } diff --git a/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx b/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx index 6688648..48fc841 100644 --- a/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx +++ b/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx @@ -13,6 +13,29 @@ import { useStageReview } from "~~/hooks/pg-ens/useStageReview"; import { useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth"; import { notification } from "~~/utils/scaffold-eth"; +const LOADING_STATUS_MAP = { + CreatingStream: "Creating grant stream", + Approving: "Approving grant", + MovingToNextStage: "Moving grant to next stage", + Empty: "", +} as const; + +const WAITING_FOR_SIGNATURE_POSTFIX = "waiting for signature"; + +type LoadingStatus = (typeof LOADING_STATUS_MAP)[keyof typeof LOADING_STATUS_MAP]; + +const getLoadingStatusText = ({ status, isWaiting }: { status: LoadingStatus; isWaiting: boolean }) => { + if (status === LOADING_STATUS_MAP.Empty) { + return status; + } + + if (isWaiting) { + return `${status}, ${WAITING_FOR_SIGNATURE_POSTFIX}...`; + } + + return `${status}...`; +}; + export const FinalApproveModal = forwardRef< HTMLDialogElement, { @@ -23,21 +46,15 @@ export const FinalApproveModal = forwardRef< grantNumber: number; } >(({ stage, grantName, builderAddress, isGrant, grantNumber }, ref) => { - const { reviewStage, isSigning, isPostingStageReview } = useStageReview(stage.id); - const isFinalApproveButtonLoading = isPostingStageReview || isSigning; + const { reviewStage, isSigning } = useStageReview(stage.id); + const [loadingStatus, setLoadingStatus] = useState(LOADING_STATUS_MAP.Empty); const { approvalVotes } = stage; - const [isAmountValidationEnabled, setIsAmountValidationEnabled] = useState(false); - const enableAmountValidation = () => { - if (!isAmountValidationEnabled) { - setIsAmountValidationEnabled(true); - } - }; const { getCommonOptions, formMethods } = useFormMethods({ schema: finalApproveModalFormSchema, }); - const { handleSubmit, getValues, setValue, trigger } = formMethods; + const { handleSubmit } = formMethods; const { writeContractAsync, isPending: isWriteContractPending } = useScaffoldWriteContract("Stream"); @@ -51,44 +68,52 @@ export const FinalApproveModal = forwardRef< }, }); - const handleSetupStream = async () => { - enableAmountValidation(); - + const handleSetupStream = async (fieldValues: FinalApproveModalFormValues) => { try { - const fieldValues = getValues(); - const isGrantAmountValid = await trigger("grantAmount", { shouldFocus: true }); - if (!isGrantAmountValid) { - return; - } - let txHash; if (isGrant) { + setLoadingStatus(LOADING_STATUS_MAP.CreatingStream); txHash = await writeContractAsync({ functionName: "addGrantStream", args: [builderAddress, parseEther(fieldValues.grantAmount), grantNumber], }); } else { - if (!contractGrantIdForBuilder) + if (!contractGrantIdForBuilder) { + setLoadingStatus(LOADING_STATUS_MAP.Empty); + return notification.error("Error getting grant for corresponding builder in contract"); + } + setLoadingStatus(LOADING_STATUS_MAP.MovingToNextStage); + txHash = await writeContractAsync({ functionName: "moveGrantToNextStage", args: [contractGrantIdForBuilder, parseEther(fieldValues.grantAmount)], }); } - if (txHash) { - setValue("txHash", txHash, { shouldValidate: false }); - } + return txHash; } catch (e) { console.error("Error sending setup transaction", e); } }; const onSubmit = async (fieldValues: FinalApproveModalFormValues) => { - await reviewStage({ status: "approved", ...fieldValues, grantNumber: grantNumber.toString() }); + const txHash = await handleSetupStream(fieldValues); + if (!txHash) { + setLoadingStatus(LOADING_STATUS_MAP.Empty); + return notification.error("Error setting up stream"); + } + setLoadingStatus(LOADING_STATUS_MAP.Approving); + await reviewStage({ status: "approved", ...fieldValues, txHash, grantNumber: grantNumber.toString() }); + setLoadingStatus(LOADING_STATUS_MAP.Empty); }; + const loadingStatusText = getLoadingStatusText({ + status: loadingStatus, + isWaiting: isSigning || isWriteContractPending, + }); + return (
@@ -118,38 +143,18 @@ export const FinalApproveModal = forwardRef< { - if (isAmountValidationEnabled) { - setValue("grantAmount", e.target.value, { shouldValidate: true }); - } - }} /> - -
- - -
+ + {loadingStatusText && ( +
+ + {loadingStatusText} +
+ )} +
diff --git a/packages/nextjs/app/admin/_components/FinalApproveModal/schema.tsx b/packages/nextjs/app/admin/_components/FinalApproveModal/schema.tsx index 402e856..438786d 100644 --- a/packages/nextjs/app/admin/_components/FinalApproveModal/schema.tsx +++ b/packages/nextjs/app/admin/_components/FinalApproveModal/schema.tsx @@ -6,7 +6,6 @@ export const finalApproveModalFormSchema = z.object({ message: "Enter valid number", }), statusNote: z.string().max(DEFAULT_TEXTAREA_MAX_LENGTH).optional(), - txHash: z.string().length(66), }); export type FinalApproveModalFormValues = z.infer; diff --git a/packages/nextjs/app/admin/_components/Proposal.tsx b/packages/nextjs/app/admin/_components/Proposal.tsx index c3cee20..4ff117c 100644 --- a/packages/nextjs/app/admin/_components/Proposal.tsx +++ b/packages/nextjs/app/admin/_components/Proposal.tsx @@ -118,8 +118,6 @@ export const Proposal = ({ proposal, userSubmissionsAmount, isGrant }: ProposalP diff --git a/packages/nextjs/app/api/stages/revalidate-status/route.ts b/packages/nextjs/app/api/stages/revalidate-status/route.ts index c0d252f..0e83586 100644 --- a/packages/nextjs/app/api/stages/revalidate-status/route.ts +++ b/packages/nextjs/app/api/stages/revalidate-status/route.ts @@ -35,7 +35,6 @@ export async function POST(request: Request) { const targetNetwork = scaffoldConfig.targetNetworks[0]; const publicClient = createPublicClient({ - // TODO: Change this while deploying chain: targetNetwork, cacheTime: 0, transport: http(getAlchemyHttpUrl(targetNetwork.id)), diff --git a/packages/nextjs/components/pg-ens/form-fields/FormInput.tsx b/packages/nextjs/components/pg-ens/form-fields/FormInput.tsx index d0f7f8a..54334fa 100644 --- a/packages/nextjs/components/pg-ens/form-fields/FormInput.tsx +++ b/packages/nextjs/components/pg-ens/form-fields/FormInput.tsx @@ -1,4 +1,3 @@ -import { ChangeEventHandler } from "react"; import { FormErrorMessage } from "./FormErrorMessage"; import { useFormContext, useWatch } from "react-hook-form"; import { DEFAULT_INPUT_MAX_LENGTH } from "~~/utils/forms"; @@ -8,13 +7,11 @@ type FormInputProps = { name: string; error?: string; required?: boolean; - onChange?: ChangeEventHandler; }; -export const FormInput = ({ error, label, name, required, onChange }: FormInputProps) => { +export const FormInput = ({ error, label, name, required }: FormInputProps) => { const { register, control } = useFormContext(); useWatch({ control, name }); - const registerProps = register(name); return (
@@ -26,8 +23,7 @@ export const FormInput = ({ error, label, name, required, onChange }: FormInputP )} { + return [ + contractName, + { + network: targetNetwork.name as string, + abi: deployedContracts[targetNetwork.id][contractName].abi, + address: deployedContracts[targetNetwork.id][contractName].address, + // TODO: Change startBlock when deploying + startBlock: + deployedContracts[targetNetwork.id][contractName].startBlock || 0, + }, + ]; + }) +); + +export default createConfig({ + networks: networks, + contracts: contracts, }); diff --git a/packages/ponder/src/StreamContract.ts b/packages/ponder/src/StreamContract.ts index ebe9ccc..e098968 100644 --- a/packages/ponder/src/StreamContract.ts +++ b/packages/ponder/src/StreamContract.ts @@ -1,6 +1,6 @@ import { ponder } from "@/generated"; -ponder.on("StreamContract:Withdraw", async ({ event, context }) => { +ponder.on("Stream:Withdraw", async ({ event, context }) => { try { const { db } = context; @@ -30,11 +30,11 @@ ponder.on("StreamContract:Withdraw", async ({ event, context }) => { builderAddress: event.args.to, contractGrantId: event.args.grantId, }, - replacer, + replacer ), }); } catch (error) { - console.log("Error in StreamContract:Withdraw", error); + console.log("Error in Stream:Withdraw", error); } }); From 7c2b14215308971b8e79d81661778e37d205277d Mon Sep 17 00:00:00 2001 From: Rinat Date: Tue, 26 Nov 2024 11:21:53 +0100 Subject: [PATCH 2/8] Fix grants order bug (#95) * update contract with multiple owner * remove this later: add sepolia contract to frontend * configure ponder * add apollo client * update sepolia deployment + fetching with apollo client * remove singature while withdrawal + featch / update data from ponder * add comments * update readme * udpate .env.development * use vercel/postgres driver * complete stage via ponder + handle edge case in new stage if ponder fails * fix date in milestone modal * update test + revert contract unlock period to 30 days * Update packages/nextjs/app/_components/ApprovedGrants/GrantMilestonesModal.tsx Co-authored-by: Pablo Alayeto <55535804+Pabl0cks@users.noreply.github.com> * use targetNetwork instead of hardcoded sepolia id and chain * Add initial ENS content and small tweaks (#71) * remove address assertion in ApprovedGrantItem * if env is prod use url from env * add comment for env * update my-grants route to parse bigint * update all 3 get api routes to parse bigint * Tweak workflow description * All grants page with filters for admins (#72) * Approval votes (#77) * Update footer and other minor tweaks (#79) Co-authored-by: Rinat * fix gratNumber mismatch (#81) * Required tg tw fields (#88) * Thumbnail and user feedback messages (#91) * chore: preconfigure hardhat * fix: grants order bug * fix: update tests * chore: eof * fix existingBuilderGrants coversion in contract * chore: remove log --------- Co-authored-by: Shiv Bhonde Co-authored-by: pabl0cks Co-authored-by: Pablo Alayeto <55535804+Pabl0cks@users.noreply.github.com> --- packages/hardhat/contracts/Stream.sol | 49 +++++++++---- packages/hardhat/deployments/sepolia/.chainId | 2 +- packages/hardhat/test/Stream.ts | 4 +- .../_components/FinalApproveModal/index.tsx | 7 +- packages/nextjs/app/api/stages/new/route.ts | 5 +- .../_components/CurrentStage/index.tsx | 8 +- packages/nextjs/app/grants/[grantId]/page.tsx | 10 +-- .../nextjs/contracts/deployedContracts.ts | 73 ++++++++----------- .../services/database/repositories/grants.ts | 26 +------ 9 files changed, 82 insertions(+), 102 deletions(-) diff --git a/packages/hardhat/contracts/Stream.sol b/packages/hardhat/contracts/Stream.sol index 59f0a26..f87d8a4 100644 --- a/packages/hardhat/contracts/Stream.sol +++ b/packages/hardhat/contracts/Stream.sol @@ -15,10 +15,15 @@ contract Stream is AccessControl { address builder; } + struct BuilderGrantData { + uint256 grantId; + uint8 grantNumber; + } + mapping(uint256 => GrantStream) public grantStreams; uint256 public nextGrantId = 1; - mapping(address => uint256[]) public builderGrants; + mapping(address => BuilderGrantData[]) public builderGrants; // uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 3 minutes uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days @@ -107,16 +112,18 @@ contract Stream is AccessControl { ) public onlyRole(OWNER_ROLE) returns (uint256) { // check if grantStream with same grantNumber already exists uint256 existingGrantId; - uint256[] memory existingBuilderGrants = builderGrants[_builder]; + BuilderGrantData[] memory existingBuilderGrants = builderGrants[ + _builder + ]; for (uint i = 0; i < existingBuilderGrants.length; i++) { GrantStream memory existingGrant = grantStreams[ - existingBuilderGrants[i] + existingBuilderGrants[i].grantId ]; if (existingGrant.grantNumber == _grantNumber) { if (existingGrant.cap != existingGrant.amountLeft) { revert AlreadyWithdrawnFromGrant(); } - existingGrantId = existingBuilderGrants[i]; + existingGrantId = existingBuilderGrants[i].grantId; break; } } @@ -136,12 +143,16 @@ contract Stream is AccessControl { }); if (existingGrantId == 0) { - builderGrants[_builder].push(grantId); + builderGrants[_builder].push( + BuilderGrantData({ + grantId: grantId, + grantNumber: _grantNumber + }) + ); emit AddGrant(grantId, _builder, _cap); } else { emit ReinitializeGrant(grantId, _builder, _cap); } - return grantId; } @@ -181,13 +192,13 @@ contract Stream is AccessControl { grantStream.amountLeft = _cap; grantStream.stageNumber += 1; - emit MoveGrantToNextStage( - _grantId, - grantStream.builder, - _cap, - grantStream.grantNumber, - grantStream.stageNumber - ); + emit MoveGrantToNextStage( + _grantId, + grantStream.builder, + _cap, + grantStream.grantNumber, + grantStream.stageNumber + ); } } @@ -264,6 +275,18 @@ contract Stream is AccessControl { emit RemoveOwner(owner, msg.sender); } + function getGrantIdByBuilderAndGrantNumber( + address _builder, + uint8 _grantNumber + ) public view returns (uint256) { + for (uint256 i = 0; i < builderGrants[_builder].length; i++) { + if (builderGrants[_builder][i].grantNumber == _grantNumber) { + return builderGrants[_builder][i].grantId; + } + } + return 0; + } + receive() external payable {} fallback() external payable {} diff --git a/packages/hardhat/deployments/sepolia/.chainId b/packages/hardhat/deployments/sepolia/.chainId index bd8d1cd..1b14418 100644 --- a/packages/hardhat/deployments/sepolia/.chainId +++ b/packages/hardhat/deployments/sepolia/.chainId @@ -1 +1 @@ -11155111 \ No newline at end of file +11155111 diff --git a/packages/hardhat/test/Stream.ts b/packages/hardhat/test/Stream.ts index 9af174d..b5faad6 100644 --- a/packages/hardhat/test/Stream.ts +++ b/packages/hardhat/test/Stream.ts @@ -202,10 +202,10 @@ describe("Stream", async () => { expect(grantCount).to.equal(2); // Access each grant - const firstGrantId = await stream.builderGrants(builder.address, 0); + const firstGrantId = await stream.getGrantIdByBuilderAndGrantNumber(builder.address, 1); expect(firstGrantId).to.equal(grantId); - const secondGrantId = await stream.builderGrants(builder.address, 1); + const secondGrantId = await stream.getGrantIdByBuilderAndGrantNumber(builder.address, 2); expect(secondGrantId).to.equal(grantId + 1n); // Trying to access a non-existent index should revert diff --git a/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx b/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx index 48fc841..94169af 100644 --- a/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx +++ b/packages/nextjs/app/admin/_components/FinalApproveModal/index.tsx @@ -58,11 +58,11 @@ export const FinalApproveModal = forwardRef< const { writeContractAsync, isPending: isWriteContractPending } = useScaffoldWriteContract("Stream"); - // we could write more robust logic to handle some edge cases. Being optimistic for now and assuming grantNumbers will be linear const { data: contractGrantIdForBuilder } = useScaffoldReadContract({ contractName: "Stream", - functionName: "builderGrants", - args: [builderAddress, BigInt(grantNumber - 1)], + functionName: "getGrantIdByBuilderAndGrantNumber", + // @ts-expect-error: grantNumber is safe to convert to BigInt + args: [builderAddress, BigInt(grantNumber)], query: { enabled: !isGrant, }, @@ -145,7 +145,6 @@ export const FinalApproveModal = forwardRef< {...getCommonOptions("grantAmount")} /> - {loadingStatusText && (
diff --git a/packages/nextjs/app/api/stages/new/route.ts b/packages/nextjs/app/api/stages/new/route.ts index f1f4339..20658f9 100644 --- a/packages/nextjs/app/api/stages/new/route.ts +++ b/packages/nextjs/app/api/stages/new/route.ts @@ -62,8 +62,9 @@ export async function POST(req: Request) { const contractGrantId = await publicClient.readContract({ ...contractConfig, - functionName: "builderGrants", - args: [grant.builderAddress, BigInt(grant.grantNumber - 1)], + functionName: "getGrantIdByBuilderAndGrantNumber", + // @ts-expect-error: grantNumber is safe to convert to BigInt + args: [grant.builderAddress, BigInt(grant.grantNumber)], }); const grantInfo = await publicClient.readContract({ diff --git a/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx b/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx index c80f8ca..a0c95ae 100644 --- a/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx +++ b/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx @@ -12,16 +12,16 @@ import { useScaffoldReadContract } from "~~/hooks/scaffold-eth"; type CurrentStageProps = { grant: NonNullable; - rejectedCount: number; }; -export const CurrentStage = ({ grant, rejectedCount }: CurrentStageProps) => { +export const CurrentStage = ({ grant }: CurrentStageProps) => { const latestStage = grant.stages[0]; const { data: contractGrantId } = useScaffoldReadContract({ contractName: "Stream", - functionName: "builderGrants", - args: [grant.builderAddress, BigInt(grant.grantNumber - rejectedCount - 1)], + functionName: "getGrantIdByBuilderAndGrantNumber", + // @ts-expect-error: grantNumber is safe to convert to BigInt + args: [grant.builderAddress, BigInt(grant.grantNumber)], }); const { diff --git a/packages/nextjs/app/grants/[grantId]/page.tsx b/packages/nextjs/app/grants/[grantId]/page.tsx index 5ecc10e..b88487c 100644 --- a/packages/nextjs/app/grants/[grantId]/page.tsx +++ b/packages/nextjs/app/grants/[grantId]/page.tsx @@ -2,7 +2,7 @@ import { CurrentStage } from "./_components/CurrentStage"; import { GrantDetails } from "./_components/GrantDetails"; import { ProjectTimeline } from "./_components/ProjectTimeline"; import { getServerSession } from "next-auth"; -import { getGrantById, getRejectedGrantsCountLessThanGrantNumber } from "~~/services/database/repositories/grants"; +import { getGrantById } from "~~/services/database/repositories/grants"; import { authOptions } from "~~/utils/auth"; export type GrantWithStages = Awaited>; @@ -12,12 +12,6 @@ const Grant = async ({ params }: { params: { grantId: string } }) => { const session = await getServerSession(authOptions); const grant = await getGrantById(grantId); - // NOTE: We use this count to correctly calculate grantNumber in contract. - // - Contract maintains `builderGrants` mapping in array where index represent grantNumber and value of that array represent grantId - // - Since we don't store rejected grants in contract, the grantsNumber will less than or equal to databse `grantNumber` - // - less than when there are rejected grants, equal when there are no rejected grants - // - hence this logic subracts all the rejecteGrants count that are less than current gratNumber, and thats how we get correct contract index (CurrentStage read contract logic) - const rejectedCount = await getRejectedGrantsCountLessThanGrantNumber(grantId); if (!grant) { return ( @@ -33,7 +27,7 @@ const Grant = async ({ params }: { params: { grantId: string } }) => {

{grant.title}

- +
); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 984303b..d6ca018 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -20,11 +20,6 @@ const deployedContracts = { stateMutability: "nonpayable", type: "constructor", }, - { - inputs: [], - name: "AlreadyWithdrawnFromGrant", - type: "error", - }, { inputs: [], name: "FailedToSendEther", @@ -136,43 +131,6 @@ const deployedContracts = { name: "MoveGrantToNextStage", type: "event", }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "builder", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "ReinitializeNextStage", - type: "event", - }, { anonymous: false, inputs: [ @@ -474,9 +432,14 @@ const deployedContracts = { outputs: [ { internalType: "uint256", - name: "", + name: "grantId", type: "uint256", }, + { + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, ], stateMutability: "view", type: "function", @@ -500,6 +463,30 @@ const deployedContracts = { stateMutability: "view", type: "function", }, + { + inputs: [ + { + internalType: "address", + name: "_builder", + type: "address", + }, + { + internalType: "uint8", + name: "_grantNumber", + type: "uint8", + }, + ], + name: "getGrantIdByBuilderAndGrantNumber", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, { inputs: [ { diff --git a/packages/nextjs/services/database/repositories/grants.ts b/packages/nextjs/services/database/repositories/grants.ts index d245c0a..825ab91 100644 --- a/packages/nextjs/services/database/repositories/grants.ts +++ b/packages/nextjs/services/database/repositories/grants.ts @@ -1,4 +1,4 @@ -import { InferInsertModel, InferSelectModel, and, count, desc, eq, lt, max } from "drizzle-orm"; +import { InferInsertModel, InferSelectModel, desc, eq, max } from "drizzle-orm"; import { db } from "~~/services/database/config/postgresClient"; import { grants, stages } from "~~/services/database/config/schema"; @@ -73,27 +73,3 @@ export async function getGrantById(grantId: number) { }, }); } - -export async function getRejectedGrantsCountLessThanGrantNumber(grantId: number) { - const grant = await db.query.grants.findFirst({ - where: eq(grants.id, grantId), - }); - - if (!grant) return 0; - - const result = await db - .select({ - count: count(), - }) - .from(grants) - .leftJoin(stages, eq(grants.id, stages.grantId)) - .where( - and( - eq(stages.status, "rejected"), - lt(grants.grantNumber, grant.grantNumber), - eq(grants.builderAddress, grant.builderAddress), - ), - ); - - return result[0].count; -} From 3c4b66ef790abc57428afc2909f94af15934273f Mon Sep 17 00:00:00 2001 From: Rinat Date: Tue, 26 Nov 2024 13:23:45 +0100 Subject: [PATCH 3/8] Remove withdrawals table (#93) Co-authored-by: Shiv Bhonde Co-authored-by: pabl0cks Co-authored-by: Pablo Alayeto <55535804+Pabl0cks@users.noreply.github.com> --- .../nextjs/services/database/config/schema.ts | 18 ------------------ .../services/database/repositories/grants.ts | 3 --- packages/nextjs/services/database/seed.ts | 3 +-- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/packages/nextjs/services/database/config/schema.ts b/packages/nextjs/services/database/config/schema.ts index 31167b6..6cb452c 100644 --- a/packages/nextjs/services/database/config/schema.ts +++ b/packages/nextjs/services/database/config/schema.ts @@ -73,23 +73,6 @@ export const approvalVotesRelations = relations(approvalVotes, ({ one }) => ({ }), })); -export const withdrawals = pgTable("withdrawals", { - id: serial("id").primaryKey(), - milestones: text("milestones"), - withdrewAt: timestamp("withdrew_at").default(sql`now()`), - stageId: integer("stage_id") - .references(() => stages.id) - .notNull(), - withdrawAmount: bigint("grantAmount", { mode: "bigint" }), -}); - -export const withdrawalsRelations = relations(withdrawals, ({ one }) => ({ - stage: one(stages, { - fields: [withdrawals.stageId], - references: [stages.id], - }), -})); - export const privateNotes = pgTable("private_notes", { id: serial("id").primaryKey(), note: text("note").notNull(), @@ -114,7 +97,6 @@ export const stagesRelations = relations(stages, ({ one, many }) => ({ fields: [stages.grantId], references: [grants.id], }), - withdrawals: many(withdrawals), privateNotes: many(privateNotes), approvalVotes: many(approvalVotes), })); diff --git a/packages/nextjs/services/database/repositories/grants.ts b/packages/nextjs/services/database/repositories/grants.ts index 825ab91..a6027e4 100644 --- a/packages/nextjs/services/database/repositories/grants.ts +++ b/packages/nextjs/services/database/repositories/grants.ts @@ -12,9 +12,6 @@ export async function getAllGrants() { stages: { // this makes sure latest stage is first orderBy: [desc(stages.stageNumber)], - with: { - withdrawals: true, - }, }, }, }); diff --git a/packages/nextjs/services/database/seed.ts b/packages/nextjs/services/database/seed.ts index 1a06bc8..d7d12c4 100644 --- a/packages/nextjs/services/database/seed.ts +++ b/packages/nextjs/services/database/seed.ts @@ -1,4 +1,4 @@ -import { approvalVotes, grants, privateNotes, stages, users, withdrawals } from "./config/schema"; +import { approvalVotes, grants, privateNotes, stages, users } from "./config/schema"; import * as schema from "./config/schema"; import * as dotenv from "dotenv"; import { drizzle } from "drizzle-orm/node-postgres"; @@ -19,7 +19,6 @@ async function seed() { await db.delete(privateNotes).execute(); // Delete private notes first await db.delete(approvalVotes).execute(); - await db.delete(withdrawals).execute(); await db.delete(stages).execute(); // Ensure stages are deleted before grants await db.delete(grants).execute(); // Delete grants await db.delete(users).execute(); From 3bfb82284ed0e875cb8d3a48051344fc272828d3 Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 27 Nov 2024 08:05:07 +0100 Subject: [PATCH 4/8] fix: withdrawals bar overflow (#100) --- .../[grantId]/_components/CurrentStage/index.tsx | 12 +++++++++--- .../nextjs/components/pg-ens/GrantProgressBar.tsx | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx b/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx index a0c95ae..588a06d 100644 --- a/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx +++ b/packages/nextjs/app/grants/[grantId]/_components/CurrentStage/index.tsx @@ -27,14 +27,18 @@ export const CurrentStage = ({ grant }: CurrentStageProps) => { const { data: contractGrantInfo, isLoading: isBuilderInfoLoading, - refetch: refetchContractInfo, + refetch: refetchGrantInfo, } = useScaffoldReadContract({ contractName: "Stream", functionName: "grantStreams", args: [contractGrantId], }); - const { data: unlockedAmount, isLoading: isUnlockedAmountLoading } = useScaffoldReadContract({ + const { + data: unlockedAmount, + isLoading: isUnlockedAmountLoading, + refetch: refetchUnlockedAmount, + } = useScaffoldReadContract({ contractName: "Stream", functionName: "unlockedGrantAmount", args: [contractGrantId], @@ -87,7 +91,9 @@ export const CurrentStage = ({ grant }: CurrentStageProps) => { stage={latestStage} closeModal={() => withdrawModalRef.current?.close()} contractGrantId={contractGrantId} - refetchContractInfo={refetchContractInfo} + refetchContractInfo={async () => { + await Promise.all([refetchGrantInfo(), refetchUnlockedAmount()]); + }} />
); diff --git a/packages/nextjs/components/pg-ens/GrantProgressBar.tsx b/packages/nextjs/components/pg-ens/GrantProgressBar.tsx index f57974c..5d3b9d5 100644 --- a/packages/nextjs/components/pg-ens/GrantProgressBar.tsx +++ b/packages/nextjs/components/pg-ens/GrantProgressBar.tsx @@ -6,7 +6,7 @@ export type GrantProgressBarProps = { }; export const GrantProgressBar = ({ amount, withdrawn = 0, available = 0, className = "" }: GrantProgressBarProps) => { - const availablePercentage = ((available + withdrawn) / amount) * 100; + const availablePercentage = (available / amount) * 100; const withdrawnPercentage = (withdrawn / amount) * 100; if (!amount) { @@ -23,7 +23,7 @@ export const GrantProgressBar = ({ amount, withdrawn = 0, available = 0, classNa />
From 1408ac4f1143a4b7346b323abe06789b17b1250c Mon Sep 17 00:00:00 2001 From: Rinat Date: Wed, 27 Nov 2024 08:08:36 +0100 Subject: [PATCH 5/8] feat: withdrawals migration (#101) --- .../migrations/0001_friendly_jimmy_woo.sql | 1 + .../migrations/meta/0001_snapshot.json | 409 ++++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + 3 files changed, 417 insertions(+) create mode 100644 packages/nextjs/services/database/migrations/0001_friendly_jimmy_woo.sql create mode 100644 packages/nextjs/services/database/migrations/meta/0001_snapshot.json diff --git a/packages/nextjs/services/database/migrations/0001_friendly_jimmy_woo.sql b/packages/nextjs/services/database/migrations/0001_friendly_jimmy_woo.sql new file mode 100644 index 0000000..db7e343 --- /dev/null +++ b/packages/nextjs/services/database/migrations/0001_friendly_jimmy_woo.sql @@ -0,0 +1 @@ +DROP TABLE "withdrawals"; \ No newline at end of file diff --git a/packages/nextjs/services/database/migrations/meta/0001_snapshot.json b/packages/nextjs/services/database/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..0602696 --- /dev/null +++ b/packages/nextjs/services/database/migrations/meta/0001_snapshot.json @@ -0,0 +1,409 @@ +{ + "id": "75d1e99a-9072-4403-b69d-0b959e4670f3", + "prevId": "dbb0e530-78f6-47f9-9b35-dabaaca3e7f5", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.approval_votes": { + "name": "approval_votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "voted_at": { + "name": "voted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "stage_id": { + "name": "stage_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "author_address": { + "name": "author_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "approval_votes_stage_id_stages_id_fk": { + "name": "approval_votes_stage_id_stages_id_fk", + "tableFrom": "approval_votes", + "tableTo": "stages", + "columnsFrom": [ + "stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "approval_votes_author_address_users_address_fk": { + "name": "approval_votes_author_address_users_address_fk", + "tableFrom": "approval_votes", + "tableTo": "users", + "columnsFrom": [ + "author_address" + ], + "columnsTo": [ + "address" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "approval_votes_stage_id_author_address_unique": { + "name": "approval_votes_stage_id_author_address_unique", + "nullsNotDistinct": false, + "columns": [ + "stage_id", + "author_address" + ] + } + } + }, + "public.grants": { + "name": "grants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "grant_number": { + "name": "grant_number", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "milestones": { + "name": "milestones", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "showcaseVideoUrl": { + "name": "showcaseVideoUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requestedFunds": { + "name": "requestedFunds", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "github": { + "name": "github", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "twitter": { + "name": "twitter", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submited_at": { + "name": "submited_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "builder_address": { + "name": "builder_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "grants_builder_address_users_address_fk": { + "name": "grants_builder_address_users_address_fk", + "tableFrom": "grants", + "tableTo": "users", + "columnsFrom": [ + "builder_address" + ], + "columnsTo": [ + "address" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.private_notes": { + "name": "private_notes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "written_at": { + "name": "written_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "stage_id": { + "name": "stage_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "author_address": { + "name": "author_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "private_notes_stage_id_stages_id_fk": { + "name": "private_notes_stage_id_stages_id_fk", + "tableFrom": "private_notes", + "tableTo": "stages", + "columnsFrom": [ + "stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "private_notes_author_address_users_address_fk": { + "name": "private_notes_author_address_users_address_fk", + "tableFrom": "private_notes", + "tableTo": "users", + "columnsFrom": [ + "author_address" + ], + "columnsTo": [ + "address" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.stages": { + "name": "stages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "stage_number": { + "name": "stage_number", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "milestone": { + "name": "milestone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submited_at": { + "name": "submited_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "grant_id": { + "name": "grant_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grantAmount": { + "name": "grantAmount", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "stage_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'proposed'" + }, + "statusNote": { + "name": "statusNote", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_tx": { + "name": "approved_tx", + "type": "varchar(66)", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "stages_grant_id_grants_id_fk": { + "name": "stages_grant_id_grants_id_fk", + "tableFrom": "stages", + "tableTo": "grants", + "columnsFrom": [ + "grant_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "role": { + "name": "role", + "type": "user_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'grantee'" + }, + "address": { + "name": "address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_address_unique": { + "name": "users_address_unique", + "nullsNotDistinct": false, + "columns": [ + "address" + ] + } + } + } + }, + "enums": { + "public.stage_status": { + "name": "stage_status", + "schema": "public", + "values": [ + "proposed", + "approved", + "completed", + "rejected" + ] + }, + "public.user_role": { + "name": "user_role", + "schema": "public", + "values": [ + "admin", + "grantee" + ] + } + }, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/nextjs/services/database/migrations/meta/_journal.json b/packages/nextjs/services/database/migrations/meta/_journal.json index 9551be3..17cb054 100644 --- a/packages/nextjs/services/database/migrations/meta/_journal.json +++ b/packages/nextjs/services/database/migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1731150282872, "tag": "0000_colossal_master_chief", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1732626708446, + "tag": "0001_friendly_jimmy_woo", + "breakpoints": true } ] } \ No newline at end of file From 384c94fb34851d6bfca91291196e6cc2889c1ec8 Mon Sep 17 00:00:00 2001 From: "Shiv Bhonde | shivbhonde.eth" Date: Wed, 27 Nov 2024 13:33:06 +0530 Subject: [PATCH 6/8] Ponder env (#102) --- packages/nextjs/app/_components/Grants/AllGrantsList.tsx | 3 ++- packages/nextjs/scaffold.config.ts | 4 ++++ packages/ponder/.env.example | 4 ++++ packages/ponder/ponder.config.ts | 5 ++--- packages/ponder/src/StreamContract.ts | 7 ++++--- 5 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 packages/ponder/.env.example diff --git a/packages/nextjs/app/_components/Grants/AllGrantsList.tsx b/packages/nextjs/app/_components/Grants/AllGrantsList.tsx index b92d2e6..ade246f 100644 --- a/packages/nextjs/app/_components/Grants/AllGrantsList.tsx +++ b/packages/nextjs/app/_components/Grants/AllGrantsList.tsx @@ -18,7 +18,8 @@ export const AllGrantsList = ({ allGrants }: AllGrantsListProps) => { const [statusFilter, setStatusFilter] = useState("all"); const maxStage = useMemo(() => { - return Math.max(...allGrants.flatMap(grant => grant.stages.map(stage => stage.stageNumber))); + const stageNumbers = allGrants.flatMap(grant => grant.stages.map(stage => stage.stageNumber)); + return stageNumbers.length > 0 ? Math.max(...stageNumbers) : 0; }, [allGrants]); const filteredGrants = useMemo(() => { diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index 011c305..c3362ea 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -7,6 +7,7 @@ export type ScaffoldConfig = { walletConnectProjectId: string; disableBurnerWalletOnLocal: boolean; onlyLocalBurnerWallet: boolean; + startBlock: number; }; const scaffoldConfig = { @@ -34,6 +35,9 @@ const scaffoldConfig = { // disable burner wallet for all networks disableBurnerWalletOnLocal: true, + + // start blocknumber for contract deployment indexing + startBlock: 0, } as const satisfies ScaffoldConfig; export default scaffoldConfig; diff --git a/packages/ponder/.env.example b/packages/ponder/.env.example new file mode 100644 index 0000000..6ccf2f0 --- /dev/null +++ b/packages/ponder/.env.example @@ -0,0 +1,4 @@ +PONDER_RPC_URL_31337=http://127.0.0.1:8545/ +PONDER_RPC_URL_10= +PONDER_RPC_URL_11155420= +APP_URL=http://localhost:3000 diff --git a/packages/ponder/ponder.config.ts b/packages/ponder/ponder.config.ts index ef4c025..bff129b 100644 --- a/packages/ponder/ponder.config.ts +++ b/packages/ponder/ponder.config.ts @@ -23,11 +23,10 @@ const contracts = Object.fromEntries( abi: deployedContracts[targetNetwork.id][contractName].abi, address: deployedContracts[targetNetwork.id][contractName].address, // TODO: Change startBlock when deploying - startBlock: - deployedContracts[targetNetwork.id][contractName].startBlock || 0, + startBlock: scaffoldConfig.startBlock || 0, }, ]; - }) + }), ); export default createConfig({ diff --git a/packages/ponder/src/StreamContract.ts b/packages/ponder/src/StreamContract.ts index e098968..d48aa5c 100644 --- a/packages/ponder/src/StreamContract.ts +++ b/packages/ponder/src/StreamContract.ts @@ -1,5 +1,7 @@ import { ponder } from "@/generated"; +const APP_URL = process.env.APP_URL || "http://localhost:3000"; + ponder.on("Stream:Withdraw", async ({ event, context }) => { try { const { db } = context; @@ -17,8 +19,7 @@ ponder.on("Stream:Withdraw", async ({ event, context }) => { }, }); - // TODO: Change url before deploying - await fetch("http://localhost:3000/api/stages/revalidate-status", { + await fetch(`${APP_URL}/api/stages/revalidate-status`, { method: "POST", headers: { "Content-Type": "application/json", @@ -30,7 +31,7 @@ ponder.on("Stream:Withdraw", async ({ event, context }) => { builderAddress: event.args.to, contractGrantId: event.args.grantId, }, - replacer + replacer, ), }); } catch (error) { From 305600510ecf64a2bf223a63ed2588144c911ea6 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 27 Nov 2024 22:53:36 +0530 Subject: [PATCH 7/8] optimism deployment --- packages/hardhat/contracts/Stream.sol | 1 - .../hardhat/deployments/optimism/Stream.json | 229 +++-- ... => 9678b3902dbd92493a7cc9d28ddcf484.json} | 2 +- packages/nextjs/.env.development | 3 - .../nextjs/contracts/deployedContracts.ts | 911 ++++++++++++++++++ packages/nextjs/scaffold.config.ts | 4 +- 6 files changed, 1088 insertions(+), 62 deletions(-) rename packages/hardhat/deployments/optimism/solcInputs/{12a05f03603bc9679d7744afc23e7a9f.json => 9678b3902dbd92493a7cc9d28ddcf484.json} (79%) delete mode 100644 packages/nextjs/.env.development diff --git a/packages/hardhat/contracts/Stream.sol b/packages/hardhat/contracts/Stream.sol index f87d8a4..476ad0c 100644 --- a/packages/hardhat/contracts/Stream.sol +++ b/packages/hardhat/contracts/Stream.sol @@ -25,7 +25,6 @@ contract Stream is AccessControl { mapping(address => BuilderGrantData[]) public builderGrants; - // uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 3 minutes uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days uint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH diff --git a/packages/hardhat/deployments/optimism/Stream.json b/packages/hardhat/deployments/optimism/Stream.json index 320cbf1..97e04eb 100644 --- a/packages/hardhat/deployments/optimism/Stream.json +++ b/packages/hardhat/deployments/optimism/Stream.json @@ -1,5 +1,5 @@ { - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "abi": [ { "inputs": [ @@ -12,6 +12,11 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [], + "name": "AlreadyWithdrawnFromGrant", + "type": "error" + }, { "inputs": [], "name": "FailedToSendEther", @@ -123,6 +128,68 @@ "name": "MoveGrantToNextStage", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ReinitializeGrant", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "grantId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "builder", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "stageNumber", + "type": "uint8" + } + ], + "name": "ReinitializeNextStage", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -424,8 +491,13 @@ "outputs": [ { "internalType": "uint256", - "name": "", + "name": "grantId", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "grantNumber", + "type": "uint8" } ], "stateMutability": "view", @@ -450,6 +522,30 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_builder", + "type": "address" + }, + { + "internalType": "uint8", + "name": "_grantNumber", + "type": "uint8" + } + ], + "name": "getGrantIdByBuilderAndGrantNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -734,22 +830,22 @@ "type": "receive" } ], - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", "receipt": { "to": null, "from": "0x55b9CB0bCf56057010b9c471e7D42d60e1111EEa", - "contractAddress": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", - "transactionIndex": 7, - "gasUsed": "1390241", - "logsBloom": "0x0000000400000000080000000000000008008000000000000000000000000000000000000000000000000100000800000000000000000000000000000010000040000000000000000000000000000000020000000000000000000000000000000000000002000c400000020000000800000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000001000000000000020000000000000000000000000000000000000000000000100000000000020000000041000000000000000000000001000000000000000000000000008002000", - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f", - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", + "contractAddress": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", + "transactionIndex": 79, + "gasUsed": "1595412", + "logsBloom": "0x0000000400000000080000000000000008008000000000000000000000000000000000000000000000000100000000000000000000000000000000000010000040000000000000000000000000000000000000000000000000000000000000000000000002000c400000020000000800000000000000000000000000000400000000000010000108000000000000000000000000000000000000100000000000002000000000000000000000000000000000000000000000001000000000000020000000000000000000000000000000000000000000000100000000000020000000001000000000000000000000001000000000000000000000000008002000", + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474", + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", "logs": [ { - "transactionIndex": 7, - "blockNumber": 127774736, - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "transactionIndex": 79, + "blockNumber": 128564237, + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "topics": [ "0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff", "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", @@ -757,14 +853,14 @@ "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e" ], "data": "0x", - "logIndex": 40, - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f" + "logIndex": 254, + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474" }, { - "transactionIndex": 7, - "blockNumber": 127774736, - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "transactionIndex": 79, + "blockNumber": 128564237, + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "topics": [ "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", @@ -772,14 +868,14 @@ "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" ], "data": "0x", - "logIndex": 41, - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f" + "logIndex": 255, + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474" }, { - "transactionIndex": 7, - "blockNumber": 127774736, - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "transactionIndex": 79, + "blockNumber": 128564237, + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "topics": [ "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", @@ -787,14 +883,14 @@ "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" ], "data": "0x", - "logIndex": 42, - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f" + "logIndex": 256, + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474" }, { - "transactionIndex": 7, - "blockNumber": 127774736, - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "transactionIndex": 79, + "blockNumber": 128564237, + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "topics": [ "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", @@ -802,14 +898,14 @@ "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" ], "data": "0x", - "logIndex": 43, - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f" + "logIndex": 257, + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474" }, { - "transactionIndex": 7, - "blockNumber": 127774736, - "transactionHash": "0xc36527c3621e9b06c51ae82df3f9fa45708b30a2560aac11ec5cc00edf6c7154", - "address": "0xDcc5DF3Ca0ECa3B78c56b9134Df293B616f26371", + "transactionIndex": 79, + "blockNumber": 128564237, + "transactionHash": "0x8cdec0edf64346e8a9aba936d87065df72e850e7e4c71f61d8c4c07fd26a2631", + "address": "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", "topics": [ "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", @@ -817,12 +913,12 @@ "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" ], "data": "0x", - "logIndex": 44, - "blockHash": "0x0819916567c7dbf61f0e2ce0c115013cf918cd93aa34da5f9f3e7e891d9f9a9f" + "logIndex": 258, + "blockHash": "0x24858a4e294efd67805c36c3f6cf05921a0b5e136e9b313675bca017897b3474" } ], - "blockNumber": 127774736, - "cumulativeGasUsed": "4008190", + "blockNumber": 128564237, + "cumulativeGasUsed": "14223145", "status": 1, "byzantium": true }, @@ -835,10 +931,10 @@ ] ], "numDeployments": 1, - "solcInputHash": "12a05f03603bc9679d7744afc23e7a9f", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_initialOwners\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientContractFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientStreamFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoActiveStream\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PreviousAmountNotFullyWithdrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AddGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addedBy\",\"type\":\"address\"}],\"name\":\"AddOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"MoveGrantToNextStage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedBy\",\"type\":\"address\"}],\"name\":\"RemoveOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"UpdateGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DUST_THRESHOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_STREAM_UNLOCK_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OWNER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_grantNumber\",\"type\":\"uint8\"}],\"name\":\"addGrantStream\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"addOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"builderGrants\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"}],\"name\":\"getBuilderGrantCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantStreams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"}],\"name\":\"moveGrantToNextStage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextGrantId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"removeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"streamWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"}],\"name\":\"unlockedGrantAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_stageNumber\",\"type\":\"uint8\"}],\"name\":\"updateGrant\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Stream.sol\":\"Stream\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => RoleData) private _roles;\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\\n * Overriding this function changes the behavior of the {onlyRole} modifier.\\n *\\n * Format of the revert message is described in {_checkRole}.\\n *\\n * _Available since v4.6._\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(account),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\\n return _roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * May emit a {RoleGranted} event.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n _roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67e3daf189111d6d5b0464ed09cf9f0605a22c4b965a7fcecd707101faff008a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/Stream.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\n\\ncontract Stream is AccessControl {\\n\\tbytes32 public constant OWNER_ROLE = keccak256(\\\"OWNER_ROLE\\\");\\n\\n\\tstruct GrantStream {\\n\\t\\tuint256 cap;\\n\\t\\tuint256 last;\\n\\t\\tuint256 amountLeft;\\n\\t\\tuint8 grantNumber;\\n\\t\\tuint8 stageNumber;\\n\\t\\taddress builder;\\n\\t}\\n\\n\\tmapping(uint256 => GrantStream) public grantStreams;\\n\\tuint256 public nextGrantId = 1;\\n\\n\\tmapping(address => uint256[]) public builderGrants;\\n\\n\\t// uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 3 minutes\\n\\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days\\n\\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\\n\\n\\tevent Withdraw(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tstring reason,\\n\\t\\tuint256 grantId,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\\n\\tevent MoveGrantToNextStage(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent UpdateGrant(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 cap,\\n\\t\\tuint256 last,\\n\\t\\tuint256 amountLeft,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddOwner(address indexed newOwner, address indexed addedBy);\\n\\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\\n\\n\\t// Custom errors\\n\\terror NoActiveStream();\\n\\terror InsufficientContractFunds();\\n\\terror UnauthorizedWithdrawal();\\n\\terror InsufficientStreamFunds();\\n\\terror FailedToSendEther();\\n\\terror PreviousAmountNotFullyWithdrawn();\\n\\n\\tconstructor(address[] memory _initialOwners) {\\n\\t\\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\\n\\t\\tfor (uint i = 0; i < _initialOwners.length; i++) {\\n\\t\\t\\t_grantRole(OWNER_ROLE, _initialOwners[i]);\\n\\t\\t}\\n\\t}\\n\\n\\tfunction unlockedGrantAmount(\\n\\t\\tuint256 _grantId\\n\\t) public view returns (uint256) {\\n\\t\\tGrantStream memory grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft == 0) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\\n\\t\\t\\tFULL_STREAM_UNLOCK_PERIOD;\\n\\n\\t\\treturn\\n\\t\\t\\tunlockedAmount > grantStream.amountLeft\\n\\t\\t\\t\\t? grantStream.amountLeft\\n\\t\\t\\t\\t: unlockedAmount;\\n\\t}\\n\\n\\tfunction addGrantStream(\\n\\t\\taddress _builder,\\n\\t\\tuint256 _cap,\\n\\t\\tuint8 _grantNumber\\n\\t) public onlyRole(OWNER_ROLE) returns (uint256) {\\n\\t\\tuint256 grantId = nextGrantId++;\\n\\t\\tgrantStreams[grantId] = GrantStream({\\n\\t\\t\\tcap: _cap,\\n\\t\\t\\tlast: block.timestamp,\\n\\t\\t\\tamountLeft: _cap,\\n\\t\\t\\tgrantNumber: _grantNumber,\\n\\t\\t\\tstageNumber: 1,\\n\\t\\t\\tbuilder: _builder\\n\\t\\t});\\n\\t\\tbuilderGrants[_builder].push(grantId);\\n\\t\\temit AddGrant(grantId, _builder, _cap);\\n\\t\\treturn grantId;\\n\\t}\\n\\n\\tfunction moveGrantToNextStage(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft > DUST_THRESHOLD)\\n\\t\\t\\trevert PreviousAmountNotFullyWithdrawn();\\n\\n\\t\\tif (grantStream.amountLeft > 0) {\\n\\t\\t\\t(bool sent, ) = payable(grantStream.builder).call{\\n\\t\\t\\t\\tvalue: grantStream.amountLeft\\n\\t\\t\\t}(\\\"\\\");\\n\\t\\t\\tif (!sent) revert FailedToSendEther();\\n\\t\\t}\\n\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = block.timestamp;\\n\\t\\tgrantStream.amountLeft = _cap;\\n\\t\\tgrantStream.stageNumber += 1;\\n\\n\\t\\temit MoveGrantToNextStage(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction updateGrant(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap,\\n\\t\\tuint256 _last,\\n\\t\\tuint256 _amountLeft,\\n\\t\\tuint8 _stageNumber\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = _last;\\n\\t\\tgrantStream.amountLeft = _amountLeft;\\n\\t\\tgrantStream.stageNumber = _stageNumber;\\n\\n\\t\\temit UpdateGrant(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.last,\\n\\t\\t\\tgrantStream.amountLeft,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction streamWithdraw(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _amount,\\n\\t\\tstring memory _reason\\n\\t) public {\\n\\t\\tif (address(this).balance < _amount) revert InsufficientContractFunds();\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\\n\\n\\t\\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\\n\\t\\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\\n\\n\\t\\tgrantStream.last = grantStream.last + timeToDeduct;\\n\\t\\tgrantStream.amountLeft -= _amount;\\n\\n\\t\\t(bool sent, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n\\t\\tif (!sent) revert FailedToSendEther();\\n\\n\\t\\temit Withdraw(\\n\\t\\t\\tmsg.sender,\\n\\t\\t\\t_amount,\\n\\t\\t\\t_reason,\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction getBuilderGrantCount(\\n\\t\\taddress _builder\\n\\t) public view returns (uint256) {\\n\\t\\treturn builderGrants[_builder].length;\\n\\t}\\n\\n\\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\\n\\t\\tgrantRole(OWNER_ROLE, newOwner);\\n\\t\\temit AddOwner(newOwner, msg.sender);\\n\\t}\\n\\n\\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\\n\\t\\trevokeRole(OWNER_ROLE, owner);\\n\\t\\temit RemoveOwner(owner, msg.sender);\\n\\t}\\n\\n\\treceive() external payable {}\\n\\n\\tfallback() external payable {}\\n}\\n\",\"keccak256\":\"0x2158c7c531a7750b4bb83d44c07cbf8194b50d4f2be9392530aca8f56a2adc71\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405260016002553480156200001657600080fd5b5060405162001867380380620018678339810160408190526200003991620001da565b620000546000805160206200184783398151915280620000bb565b60005b8151811015620000b3576200009e600080516020620018478339815191528383815181106200008a576200008a620002ac565b60200260200101516200010660201b60201c565b80620000aa81620002c2565b91505062000057565b5050620002ea565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001a3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620001d557600080fd5b919050565b60006020808385031215620001ee57600080fd5b82516001600160401b03808211156200020657600080fd5b818501915085601f8301126200021b57600080fd5b815181811115620002305762000230620001a7565b8060051b604051601f19603f83011681018181108582111715620002585762000258620001a7565b6040529182528482019250838101850191888311156200027757600080fd5b938501935b82851015620002a0576200029085620001bd565b845293850193928501926200027c565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620002e357634e487b7160e01b600052601160045260246000fd5b5060010190565b61154d80620002fa6000396000f3fe6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea91461032a578063d547741f14610340578063dd7dc9a914610360578063e58378bb1461037b578063ed2c9d091461039d578063f1f693d11461043a57005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110af565b610470565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f5565b6104a7565b34801561018c57600080fd5b506101b061019b366004611110565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611129565b610511565b3480156101ea57600080fd5b506101296101f9366004611129565b61053b565b34801561020a57600080fd5b50610129610219366004611155565b6105be565b34801561022a57600080fd5b506101b0610239366004611188565b61076e565b34801561024a57600080fd5b506101296102593660046111da565b610918565b34801561026a57600080fd5b506101296102793660046110f5565b610aeb565b34801561028a57600080fd5b506101b0610299366004611110565b610b55565b3480156102aa57600080fd5b506101296102b936600461129e565b610c42565b3480156102ca57600080fd5b5061014b6102d9366004611129565b610d2c565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e7565b610d55565b34801561031f57600080fd5b506101b062278d0081565b34801561033657600080fd5b506101b060025481565b34801561034c57600080fd5b5061012961035b366004611129565b610d86565b34801561036c57600080fd5b506101b066038d7ea4c6800081565b34801561038757600080fd5b506101b06000805160206114f883398151915281565b3480156103a957600080fd5b506103fe6103b8366004611110565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044657600080fd5b506101b06104553660046110f5565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b14806104a157506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f88339815191526104bf81610dab565b6104d76000805160206114f883398151915283610d86565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052c81610dab565b6105368383610db8565b505050565b6001600160a01b03811633146105b05760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105ba8282610e3c565b5050565b6000805160206114f88339815191526105d681610dab565b6000838152600160205260408120805490910361060657604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106325760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106be57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610695576040519150601f19603f3d011682016040523d82523d6000602084013e61069a565b606091505b50509050806106bc57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106ed908290610100900460ff16611327565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f883398151915261078881610dab565b600280546000918261079983611340565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090791815260200190565b60405180910390a395945050505050565b814710156109395760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096957604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099c576040516360b39bc560e01b815260040160405180910390fd5b60006109a785610b55565b9050838110156109ca5760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109dc9190611359565b90506000826109eb878461136c565b6109f59190611383565b9050808460010154610a0791906113a5565b846001018190555085846002016000828254610a239190611359565b9091555050604051600090339088908381818185875af1925050503d8060008114610a6a576040519150601f19603f3d011682016040523d82523d6000602084013e610a6f565b606091505b5050905080610a9157604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad9918b918b918e9160ff8083169261010090041690611408565b60405180910390a25050505050505050565b6000805160206114f8833981519152610b0381610dab565b610b1b6000805160206114f883398151915283610511565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd757604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bec5750600092915050565b6000816020015142610bfe9190611359565b9050600062278d00828460000151610c16919061136c565b610c209190611383565b905082604001518111610c335780610c39565b82604001515b95945050505050565b6000805160206114f8833981519152610c5a81610dab565b60008681526001602052604081208054909103610c8a57604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d7157600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610da181610dab565b6105368383610e3c565b610db58133610ea1565b50565b610dc28282610d2c565b6105ba576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df83390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e468282610d2c565b156105ba576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610eab8282610d2c565b6105ba57610eb881610efa565b610ec3836020610f0c565b604051602001610ed4929190611442565b60408051601f198184030181529082905262461bcd60e51b82526105a7916004016114b7565b60606104a16001600160a01b03831660145b60606000610f1b83600261136c565b610f269060026113a5565b67ffffffffffffffff811115610f3e57610f3e6111c4565b6040519080825280601f01601f191660200182016040528015610f68576020820181803683370190505b509050600360fc1b81600081518110610f8357610f836114ca565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fb257610fb26114ca565b60200101906001600160f81b031916908160001a9053506000610fd684600261136c565b610fe19060016113a5565b90505b6001811115611059576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611015576110156114ca565b1a60f81b82828151811061102b5761102b6114ca565b60200101906001600160f81b031916908160001a90535060049490941c93611052816114e0565b9050610fe4565b5083156110a85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a7565b9392505050565b6000602082840312156110c157600080fd5b81356001600160e01b0319811681146110a857600080fd5b80356001600160a01b03811681146110f057600080fd5b919050565b60006020828403121561110757600080fd5b6110a8826110d9565b60006020828403121561112257600080fd5b5035919050565b6000806040838503121561113c57600080fd5b8235915061114c602084016110d9565b90509250929050565b6000806040838503121561116857600080fd5b50508035926020909101359150565b803560ff811681146110f057600080fd5b60008060006060848603121561119d57600080fd5b6111a6846110d9565b9250602084013591506111bb60408501611177565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111ef57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121557600080fd5b818601915086601f83011261122957600080fd5b81358181111561123b5761123b6111c4565b604051601f8201601f19908116603f01168101908382118183101715611263576112636111c4565b8160405282815289602084870101111561127c57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b657600080fd5b853594506020860135935060408601359250606086013591506112db60808701611177565b90509295509295909350565b600080604083850312156112fa57600080fd5b611303836110d9565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff81811683821601908111156104a1576104a1611311565b60006001820161135257611352611311565b5060010190565b818103818111156104a1576104a1611311565b80820281158282048414176104a1576104a1611311565b6000826113a057634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156104a1576104a1611311565b60005b838110156113d35781810151838201526020016113bb565b50506000910152565b600081518084526113f48160208601602086016113b8565b601f01601f19169290920160200192915050565b85815260a06020820152600061142160a08301876113dc565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161147a8160178501602088016113b8565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114ab8160288401602088016113b8565b01602801949350505050565b6020815260006110a860208301846113dc565b634e487b7160e01b600052603260045260246000fd5b6000816114ef576114ef611311565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220309501bcbac8578f0394b229dcfdf3f0dc4158ff5ee8e4bf5a9fc4df296c2d6764736f6c63430008110033b19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "deployedBytecode": "0x6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea91461032a578063d547741f14610340578063dd7dc9a914610360578063e58378bb1461037b578063ed2c9d091461039d578063f1f693d11461043a57005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110af565b610470565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f5565b6104a7565b34801561018c57600080fd5b506101b061019b366004611110565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611129565b610511565b3480156101ea57600080fd5b506101296101f9366004611129565b61053b565b34801561020a57600080fd5b50610129610219366004611155565b6105be565b34801561022a57600080fd5b506101b0610239366004611188565b61076e565b34801561024a57600080fd5b506101296102593660046111da565b610918565b34801561026a57600080fd5b506101296102793660046110f5565b610aeb565b34801561028a57600080fd5b506101b0610299366004611110565b610b55565b3480156102aa57600080fd5b506101296102b936600461129e565b610c42565b3480156102ca57600080fd5b5061014b6102d9366004611129565b610d2c565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e7565b610d55565b34801561031f57600080fd5b506101b062278d0081565b34801561033657600080fd5b506101b060025481565b34801561034c57600080fd5b5061012961035b366004611129565b610d86565b34801561036c57600080fd5b506101b066038d7ea4c6800081565b34801561038757600080fd5b506101b06000805160206114f883398151915281565b3480156103a957600080fd5b506103fe6103b8366004611110565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044657600080fd5b506101b06104553660046110f5565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b14806104a157506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f88339815191526104bf81610dab565b6104d76000805160206114f883398151915283610d86565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052c81610dab565b6105368383610db8565b505050565b6001600160a01b03811633146105b05760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105ba8282610e3c565b5050565b6000805160206114f88339815191526105d681610dab565b6000838152600160205260408120805490910361060657604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106325760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106be57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610695576040519150601f19603f3d011682016040523d82523d6000602084013e61069a565b606091505b50509050806106bc57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106ed908290610100900460ff16611327565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f883398151915261078881610dab565b600280546000918261079983611340565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090791815260200190565b60405180910390a395945050505050565b814710156109395760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096957604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099c576040516360b39bc560e01b815260040160405180910390fd5b60006109a785610b55565b9050838110156109ca5760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109dc9190611359565b90506000826109eb878461136c565b6109f59190611383565b9050808460010154610a0791906113a5565b846001018190555085846002016000828254610a239190611359565b9091555050604051600090339088908381818185875af1925050503d8060008114610a6a576040519150601f19603f3d011682016040523d82523d6000602084013e610a6f565b606091505b5050905080610a9157604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad9918b918b918e9160ff8083169261010090041690611408565b60405180910390a25050505050505050565b6000805160206114f8833981519152610b0381610dab565b610b1b6000805160206114f883398151915283610511565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd757604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bec5750600092915050565b6000816020015142610bfe9190611359565b9050600062278d00828460000151610c16919061136c565b610c209190611383565b905082604001518111610c335780610c39565b82604001515b95945050505050565b6000805160206114f8833981519152610c5a81610dab565b60008681526001602052604081208054909103610c8a57604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d7157600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610da181610dab565b6105368383610e3c565b610db58133610ea1565b50565b610dc28282610d2c565b6105ba576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df83390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e468282610d2c565b156105ba576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610eab8282610d2c565b6105ba57610eb881610efa565b610ec3836020610f0c565b604051602001610ed4929190611442565b60408051601f198184030181529082905262461bcd60e51b82526105a7916004016114b7565b60606104a16001600160a01b03831660145b60606000610f1b83600261136c565b610f269060026113a5565b67ffffffffffffffff811115610f3e57610f3e6111c4565b6040519080825280601f01601f191660200182016040528015610f68576020820181803683370190505b509050600360fc1b81600081518110610f8357610f836114ca565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fb257610fb26114ca565b60200101906001600160f81b031916908160001a9053506000610fd684600261136c565b610fe19060016113a5565b90505b6001811115611059576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611015576110156114ca565b1a60f81b82828151811061102b5761102b6114ca565b60200101906001600160f81b031916908160001a90535060049490941c93611052816114e0565b9050610fe4565b5083156110a85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a7565b9392505050565b6000602082840312156110c157600080fd5b81356001600160e01b0319811681146110a857600080fd5b80356001600160a01b03811681146110f057600080fd5b919050565b60006020828403121561110757600080fd5b6110a8826110d9565b60006020828403121561112257600080fd5b5035919050565b6000806040838503121561113c57600080fd5b8235915061114c602084016110d9565b90509250929050565b6000806040838503121561116857600080fd5b50508035926020909101359150565b803560ff811681146110f057600080fd5b60008060006060848603121561119d57600080fd5b6111a6846110d9565b9250602084013591506111bb60408501611177565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111ef57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121557600080fd5b818601915086601f83011261122957600080fd5b81358181111561123b5761123b6111c4565b604051601f8201601f19908116603f01168101908382118183101715611263576112636111c4565b8160405282815289602084870101111561127c57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b657600080fd5b853594506020860135935060408601359250606086013591506112db60808701611177565b90509295509295909350565b600080604083850312156112fa57600080fd5b611303836110d9565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff81811683821601908111156104a1576104a1611311565b60006001820161135257611352611311565b5060010190565b818103818111156104a1576104a1611311565b80820281158282048414176104a1576104a1611311565b6000826113a057634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156104a1576104a1611311565b60005b838110156113d35781810151838201526020016113bb565b50506000910152565b600081518084526113f48160208601602086016113b8565b601f01601f19169290920160200192915050565b85815260a06020820152600061142160a08301876113dc565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161147a8160178501602088016113b8565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114ab8160288401602088016113b8565b01602801949350505050565b6020815260006110a860208301846113dc565b634e487b7160e01b600052603260045260246000fd5b6000816114ef576114ef611311565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220309501bcbac8578f0394b229dcfdf3f0dc4158ff5ee8e4bf5a9fc4df296c2d6764736f6c63430008110033", + "solcInputHash": "9678b3902dbd92493a7cc9d28ddcf484", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_initialOwners\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyWithdrawnFromGrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientContractFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientStreamFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoActiveStream\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PreviousAmountNotFullyWithdrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AddGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addedBy\",\"type\":\"address\"}],\"name\":\"AddOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"MoveGrantToNextStage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ReinitializeGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"ReinitializeNextStage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedBy\",\"type\":\"address\"}],\"name\":\"RemoveOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"UpdateGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DUST_THRESHOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_STREAM_UNLOCK_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OWNER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_grantNumber\",\"type\":\"uint8\"}],\"name\":\"addGrantStream\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"addOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"builderGrants\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"}],\"name\":\"getBuilderGrantCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_grantNumber\",\"type\":\"uint8\"}],\"name\":\"getGrantIdByBuilderAndGrantNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantStreams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"}],\"name\":\"moveGrantToNextStage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextGrantId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"removeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"streamWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"}],\"name\":\"unlockedGrantAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_stageNumber\",\"type\":\"uint8\"}],\"name\":\"updateGrant\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Stream.sol\":\"Stream\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => RoleData) private _roles;\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\\n * Overriding this function changes the behavior of the {onlyRole} modifier.\\n *\\n * Format of the revert message is described in {_checkRole}.\\n *\\n * _Available since v4.6._\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(account),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\\n return _roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * May emit a {RoleGranted} event.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n _roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67e3daf189111d6d5b0464ed09cf9f0605a22c4b965a7fcecd707101faff008a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/Stream.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\n\\ncontract Stream is AccessControl {\\n\\tbytes32 public constant OWNER_ROLE = keccak256(\\\"OWNER_ROLE\\\");\\n\\n\\tstruct GrantStream {\\n\\t\\tuint256 cap;\\n\\t\\tuint256 last;\\n\\t\\tuint256 amountLeft;\\n\\t\\tuint8 grantNumber;\\n\\t\\tuint8 stageNumber;\\n\\t\\taddress builder;\\n\\t}\\n\\n\\tstruct BuilderGrantData {\\n\\t\\tuint256 grantId;\\n\\t\\tuint8 grantNumber;\\n\\t}\\n\\n\\tmapping(uint256 => GrantStream) public grantStreams;\\n\\tuint256 public nextGrantId = 1;\\n\\n\\tmapping(address => BuilderGrantData[]) public builderGrants;\\n\\n\\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days\\n\\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\\n\\n\\tevent Withdraw(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tstring reason,\\n\\t\\tuint256 grantId,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\\n\\tevent ReinitializeGrant(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount\\n\\t);\\n\\tevent MoveGrantToNextStage(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent ReinitializeNextStage(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed builder,\\n\\t\\tuint256 amount,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent UpdateGrant(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 cap,\\n\\t\\tuint256 last,\\n\\t\\tuint256 amountLeft,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddOwner(address indexed newOwner, address indexed addedBy);\\n\\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\\n\\n\\t// Custom errors\\n\\terror NoActiveStream();\\n\\terror InsufficientContractFunds();\\n\\terror UnauthorizedWithdrawal();\\n\\terror InsufficientStreamFunds();\\n\\terror FailedToSendEther();\\n\\terror PreviousAmountNotFullyWithdrawn();\\n\\terror AlreadyWithdrawnFromGrant();\\n\\n\\tconstructor(address[] memory _initialOwners) {\\n\\t\\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\\n\\t\\tfor (uint i = 0; i < _initialOwners.length; i++) {\\n\\t\\t\\t_grantRole(OWNER_ROLE, _initialOwners[i]);\\n\\t\\t}\\n\\t}\\n\\n\\tfunction unlockedGrantAmount(\\n\\t\\tuint256 _grantId\\n\\t) public view returns (uint256) {\\n\\t\\tGrantStream memory grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft == 0) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\\n\\t\\t\\tFULL_STREAM_UNLOCK_PERIOD;\\n\\n\\t\\treturn\\n\\t\\t\\tunlockedAmount > grantStream.amountLeft\\n\\t\\t\\t\\t? grantStream.amountLeft\\n\\t\\t\\t\\t: unlockedAmount;\\n\\t}\\n\\n\\tfunction addGrantStream(\\n\\t\\taddress _builder,\\n\\t\\tuint256 _cap,\\n\\t\\tuint8 _grantNumber\\n\\t) public onlyRole(OWNER_ROLE) returns (uint256) {\\n\\t\\t// check if grantStream with same grantNumber already exists\\n\\t\\tuint256 existingGrantId;\\n\\t\\tBuilderGrantData[] memory existingBuilderGrants = builderGrants[\\n\\t\\t\\t_builder\\n\\t\\t];\\n\\t\\tfor (uint i = 0; i < existingBuilderGrants.length; i++) {\\n\\t\\t\\tGrantStream memory existingGrant = grantStreams[\\n\\t\\t\\t\\texistingBuilderGrants[i].grantId\\n\\t\\t\\t];\\n\\t\\t\\tif (existingGrant.grantNumber == _grantNumber) {\\n\\t\\t\\t\\tif (existingGrant.cap != existingGrant.amountLeft) {\\n\\t\\t\\t\\t\\trevert AlreadyWithdrawnFromGrant();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\texistingGrantId = existingBuilderGrants[i].grantId;\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t// update existing grant or create new one\\n\\t\\tuint256 grantId = existingGrantId != 0\\n\\t\\t\\t? existingGrantId\\n\\t\\t\\t: nextGrantId++;\\n\\n\\t\\tgrantStreams[grantId] = GrantStream({\\n\\t\\t\\tcap: _cap,\\n\\t\\t\\tlast: block.timestamp,\\n\\t\\t\\tamountLeft: _cap,\\n\\t\\t\\tgrantNumber: _grantNumber,\\n\\t\\t\\tstageNumber: 1,\\n\\t\\t\\tbuilder: _builder\\n\\t\\t});\\n\\n\\t\\tif (existingGrantId == 0) {\\n\\t\\t\\tbuilderGrants[_builder].push(\\n\\t\\t\\t\\tBuilderGrantData({\\n\\t\\t\\t\\t\\tgrantId: grantId,\\n\\t\\t\\t\\t\\tgrantNumber: _grantNumber\\n\\t\\t\\t\\t})\\n\\t\\t\\t);\\n\\t\\t\\temit AddGrant(grantId, _builder, _cap);\\n\\t\\t} else {\\n\\t\\t\\temit ReinitializeGrant(grantId, _builder, _cap);\\n\\t\\t}\\n\\t\\treturn grantId;\\n\\t}\\n\\n\\tfunction moveGrantToNextStage(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\t// If amountLeft equals cap, reinitialize with same stage number\\n\\t\\tif (grantStream.amountLeft == grantStream.cap) {\\n\\t\\t\\tgrantStream.cap = _cap;\\n\\t\\t\\tgrantStream.last = block.timestamp;\\n\\t\\t\\tgrantStream.amountLeft = _cap;\\n\\t\\t\\t// Stage number remains the same\\n\\t\\t\\temit ReinitializeNextStage(\\n\\t\\t\\t\\t_grantId,\\n\\t\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t\\t_cap,\\n\\t\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\t\\tgrantStream.stageNumber\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tif (grantStream.amountLeft > DUST_THRESHOLD)\\n\\t\\t\\t\\trevert PreviousAmountNotFullyWithdrawn();\\n\\n\\t\\t\\tif (grantStream.amountLeft > 0) {\\n\\t\\t\\t\\t(bool sent, ) = payable(grantStream.builder).call{\\n\\t\\t\\t\\t\\tvalue: grantStream.amountLeft\\n\\t\\t\\t\\t}(\\\"\\\");\\n\\t\\t\\t\\tif (!sent) revert FailedToSendEther();\\n\\t\\t\\t}\\n\\n\\t\\t\\tgrantStream.cap = _cap;\\n\\t\\t\\tgrantStream.last = block.timestamp;\\n\\t\\t\\tgrantStream.amountLeft = _cap;\\n\\t\\t\\tgrantStream.stageNumber += 1;\\n\\n\\t\\t\\temit MoveGrantToNextStage(\\n\\t\\t\\t\\t_grantId,\\n\\t\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t\\t_cap,\\n\\t\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\t\\tgrantStream.stageNumber\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n\\n\\tfunction updateGrant(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap,\\n\\t\\tuint256 _last,\\n\\t\\tuint256 _amountLeft,\\n\\t\\tuint8 _stageNumber\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = _last;\\n\\t\\tgrantStream.amountLeft = _amountLeft;\\n\\t\\tgrantStream.stageNumber = _stageNumber;\\n\\n\\t\\temit UpdateGrant(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.last,\\n\\t\\t\\tgrantStream.amountLeft,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction streamWithdraw(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _amount,\\n\\t\\tstring memory _reason\\n\\t) public {\\n\\t\\tif (address(this).balance < _amount) revert InsufficientContractFunds();\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\\n\\n\\t\\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\\n\\t\\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\\n\\n\\t\\tgrantStream.last = grantStream.last + timeToDeduct;\\n\\t\\tgrantStream.amountLeft -= _amount;\\n\\n\\t\\t(bool sent, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n\\t\\tif (!sent) revert FailedToSendEther();\\n\\n\\t\\temit Withdraw(\\n\\t\\t\\tmsg.sender,\\n\\t\\t\\t_amount,\\n\\t\\t\\t_reason,\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction getBuilderGrantCount(\\n\\t\\taddress _builder\\n\\t) public view returns (uint256) {\\n\\t\\treturn builderGrants[_builder].length;\\n\\t}\\n\\n\\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\\n\\t\\tgrantRole(OWNER_ROLE, newOwner);\\n\\t\\temit AddOwner(newOwner, msg.sender);\\n\\t}\\n\\n\\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\\n\\t\\trevokeRole(OWNER_ROLE, owner);\\n\\t\\temit RemoveOwner(owner, msg.sender);\\n\\t}\\n\\n\\tfunction getGrantIdByBuilderAndGrantNumber(\\n\\t\\taddress _builder,\\n\\t\\tuint8 _grantNumber\\n\\t) public view returns (uint256) {\\n\\t\\tfor (uint256 i = 0; i < builderGrants[_builder].length; i++) {\\n\\t\\t\\tif (builderGrants[_builder][i].grantNumber == _grantNumber) {\\n\\t\\t\\t\\treturn builderGrants[_builder][i].grantId;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treceive() external payable {}\\n\\n\\tfallback() external payable {}\\n}\\n\",\"keccak256\":\"0x5a1104b144ef81e9b20458ea454f3e7829eafb50df78afc5af2a741887614ae9\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405260016002553480156200001657600080fd5b5060405162001c1d38038062001c1d8339810160408190526200003991620001da565b6200005460008051602062001bfd83398151915280620000bb565b60005b8151811015620000b3576200009e60008051602062001bfd8339815191528383815181106200008a576200008a620002ac565b60200260200101516200010660201b60201c565b80620000aa81620002c2565b91505062000057565b5050620002ea565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001a3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620001d557600080fd5b919050565b60006020808385031215620001ee57600080fd5b82516001600160401b03808211156200020657600080fd5b818501915085601f8301126200021b57600080fd5b815181811115620002305762000230620001a7565b8060051b604051601f19603f83011681018181108582111715620002585762000258620001a7565b6040529182528482019250838101850191888311156200027757600080fd5b938501935b82851015620002a0576200029085620001bd565b845293850193928501926200027c565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620002e357634e487b7160e01b600052601160045260246000fd5b5060010190565b61190380620002fa6000396000f3fe60806040526004361061012d5760003560e01c806391d14854116100a5578063bb8b3ea91161006c578063bb8b3ea91461036c578063d547741f14610382578063dd7dc9a9146103a2578063e58378bb146103bd578063ed2c9d09146103df578063f1f693d11461047c57005b806391d14854146102c9578063a217fddf146102e9578063ae69f6db146102fe578063b493eca114610335578063baf57b801461034c57005b8063378c3286116100f4578063378c328614610209578063543d55d5146102295780636770c53f146102495780637065cb48146102695780637370c224146102895780638f9eb24d146102a957005b806301ffc9a714610136578063173825d91461016b578063248a9ca31461018b5780632f2ff15d146101c957806336568abe146101e957005b3661013457005b005b34801561014257600080fd5b5061015661015136600461143b565b6104b2565b60405190151581526020015b60405180910390f35b34801561017757600080fd5b50610134610186366004611481565b6104e9565b34801561019757600080fd5b506101bb6101a636600461149c565b60009081526020819052604090206001015490565b604051908152602001610162565b3480156101d557600080fd5b506101346101e43660046114b5565b610553565b3480156101f557600080fd5b506101346102043660046114b5565b61057d565b34801561021557600080fd5b506101346102243660046114e1565b610600565b34801561023557600080fd5b506101bb610244366004611514565b610835565b34801561025557600080fd5b50610134610264366004611566565b610bc6565b34801561027557600080fd5b50610134610284366004611481565b610d99565b34801561029557600080fd5b506101bb6102a436600461149c565b610e03565b3480156102b557600080fd5b506101346102c436600461162a565b610ef0565b3480156102d557600080fd5b506101566102e43660046114b5565b610fda565b3480156102f557600080fd5b506101bb600081565b34801561030a57600080fd5b5061031e610319366004611673565b611003565b6040805192835260ff909116602083015201610162565b34801561034157600080fd5b506101bb62278d0081565b34801561035857600080fd5b506101bb61036736600461169d565b611042565b34801561037857600080fd5b506101bb60025481565b34801561038e57600080fd5b5061013461039d3660046114b5565b611112565b3480156103ae57600080fd5b506101bb66038d7ea4c6800081565b3480156103c957600080fd5b506101bb6000805160206118ae83398151915281565b3480156103eb57600080fd5b506104406103fa36600461149c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610162565b34801561048857600080fd5b506101bb610497366004611481565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b14806104e357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206118ae83398151915261050181611137565b6105196000805160206118ae83398151915283611112565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461056e81611137565b6105788383611144565b505050565b6001600160a01b03811633146105f25760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105fc82826111c8565b5050565b6000805160206118ae83398151915261061881611137565b6000838152600160205260408120805490910361064857604051631b017f1760e11b815260040160405180910390fd5b80546002820154036106cc578281554260018201556002810183905560038101546040805185815260ff808416602083015261010084041691810191909152620100009091046001600160a01b03169085907f163d2dff0921e64458fa28a275a08ecb86f62058df960fcd1e199a61db8f8ddd9060600160405180910390a361082f565b66038d7ea4c68000816002015411156106f85760405163d4eff9fb60e01b815260040160405180910390fd5b60028101541561078457600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d806000811461075b576040519150601f19603f3d011682016040523d82523d6000602084013e610760565b606091505b505090508061078257604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906107b3908290610100900460ff166116dd565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a35b50505050565b60006000805160206118ae83398151915261084f81611137565b6001600160a01b038516600090815260036020908152604080832080548251818502810185019093528083528493849084015b828210156108c457600084815260209081902060408051808201909152600285029091018054825260019081015460ff16828401529083529092019101610882565b50505050905060005b81518110156109cb576000600160008484815181106108ee576108ee6116f6565b602090810291909101810151518252818101929092526040908101600020815160c081018352815481526001820154938101939093526002810154918301919091526003015460ff80821660608401819052610100830482166080850152620100009092046001600160a01b031660a084015291925090881690036109b857604081015181511461099257604051630644429360e01b815260040160405180910390fd5b8282815181106109a4576109a46116f6565b6020026020010151600001519350506109cb565b50806109c38161170c565b9150506108cd565b506000826000036109ef57600280549060006109e68361170c565b919050556109f1565b825b90506040518060c001604052808881526020014281526020018881526020018760ff168152602001600160ff168152602001896001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505082600003610b76576001600160a01b03881660008181526003602090815260408083208151808301835286815260ff8c81168286019081528354600180820186559488529686902092516002909702909201958655905194909101805460ff19169490911693909317909255905189815283917f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c910160405180910390a3610bbb565b876001600160a01b0316817f10fb48f0711b494fdbf819e97c500458db3e7873b7d01e20cc3084293f25191e89604051610bb291815260200190565b60405180910390a35b979650505050505050565b81471015610be75760405163a3fb8f9d60e01b815260040160405180910390fd5b60008381526001602052604081208054909103610c1757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b03163314610c4a576040516360b39bc560e01b815260040160405180910390fd5b6000610c5585610e03565b905083811015610c785760405163347efb5160e01b815260040160405180910390fd5b6000826001015442610c8a9190611725565b9050600082610c998784611738565b610ca3919061174f565b9050808460010154610cb59190611771565b846001018190555085846002016000828254610cd19190611725565b9091555050604051600090339088908381818185875af1925050503d8060008114610d18576040519150601f19603f3d011682016040523d82523d6000602084013e610d1d565b606091505b5050905080610d3f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610d87918b918b918e9160ff80831692610100900416906117d4565b60405180910390a25050505050505050565b6000805160206118ae833981519152610db181611137565b610dc96000805160206118ae83398151915283610553565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610e8557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610e9a5750600092915050565b6000816020015142610eac9190611725565b9050600062278d00828460000151610ec49190611738565b610ece919061174f565b905082604001518111610ee15780610ee7565b82604001515b95945050505050565b6000805160206118ae833981519152610f0881611137565b60008681526001602052604081208054909103610f3857604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6003602052816000526040600020818154811061101f57600080fd5b60009182526020909120600290910201805460019091015490925060ff16905082565b6000805b6001600160a01b038416600090815260036020526040902054811015611108576001600160a01b0384166000908152600360205260409020805460ff8516919083908110611096576110966116f6565b600091825260209091206001600290920201015460ff16036110f6576001600160a01b03841660009081526003602052604090208054829081106110dc576110dc6116f6565b9060005260206000209060020201600001549150506104e3565b806111008161170c565b915050611046565b5060009392505050565b60008281526020819052604090206001015461112d81611137565b61057883836111c8565b611141813361122d565b50565b61114e8282610fda565b6105fc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556111843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6111d28282610fda565b156105fc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6112378282610fda565b6105fc5761124481611286565b61124f836020611298565b60405160200161126092919061180e565b60408051601f198184030181529082905262461bcd60e51b82526105e991600401611883565b60606104e36001600160a01b03831660145b606060006112a7836002611738565b6112b2906002611771565b67ffffffffffffffff8111156112ca576112ca611550565b6040519080825280601f01601f1916602001820160405280156112f4576020820181803683370190505b509050600360fc1b8160008151811061130f5761130f6116f6565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061133e5761133e6116f6565b60200101906001600160f81b031916908160001a9053506000611362846002611738565b61136d906001611771565b90505b60018111156113e5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113a1576113a16116f6565b1a60f81b8282815181106113b7576113b76116f6565b60200101906001600160f81b031916908160001a90535060049490941c936113de81611896565b9050611370565b5083156114345760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105e9565b9392505050565b60006020828403121561144d57600080fd5b81356001600160e01b03198116811461143457600080fd5b80356001600160a01b038116811461147c57600080fd5b919050565b60006020828403121561149357600080fd5b61143482611465565b6000602082840312156114ae57600080fd5b5035919050565b600080604083850312156114c857600080fd5b823591506114d860208401611465565b90509250929050565b600080604083850312156114f457600080fd5b50508035926020909101359150565b803560ff8116811461147c57600080fd5b60008060006060848603121561152957600080fd5b61153284611465565b92506020840135915061154760408501611503565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561157b57600080fd5b8335925060208401359150604084013567ffffffffffffffff808211156115a157600080fd5b818601915086601f8301126115b557600080fd5b8135818111156115c7576115c7611550565b604051601f8201601f19908116603f011681019083821181831017156115ef576115ef611550565b8160405282815289602084870101111561160857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a0868803121561164257600080fd5b8535945060208601359350604086013592506060860135915061166760808701611503565b90509295509295909350565b6000806040838503121561168657600080fd5b61168f83611465565b946020939093013593505050565b600080604083850312156116b057600080fd5b6116b983611465565b91506114d860208401611503565b634e487b7160e01b600052601160045260246000fd5b60ff81811683821601908111156104e3576104e36116c7565b634e487b7160e01b600052603260045260246000fd5b60006001820161171e5761171e6116c7565b5060010190565b818103818111156104e3576104e36116c7565b80820281158282048414176104e3576104e36116c7565b60008261176c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156104e3576104e36116c7565b60005b8381101561179f578181015183820152602001611787565b50506000910152565b600081518084526117c0816020860160208601611784565b601f01601f19169290920160200192915050565b85815260a0602082015260006117ed60a08301876117a8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611846816017850160208801611784565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611877816028840160208801611784565b01602801949350505050565b60208152600061143460208301846117a8565b6000816118a5576118a56116c7565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220696172ba62ce09f5bf965770b353446ba592ec037821a87e4bd0133c062fe38564736f6c63430008110033b19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", + "deployedBytecode": "0x60806040526004361061012d5760003560e01c806391d14854116100a5578063bb8b3ea91161006c578063bb8b3ea91461036c578063d547741f14610382578063dd7dc9a9146103a2578063e58378bb146103bd578063ed2c9d09146103df578063f1f693d11461047c57005b806391d14854146102c9578063a217fddf146102e9578063ae69f6db146102fe578063b493eca114610335578063baf57b801461034c57005b8063378c3286116100f4578063378c328614610209578063543d55d5146102295780636770c53f146102495780637065cb48146102695780637370c224146102895780638f9eb24d146102a957005b806301ffc9a714610136578063173825d91461016b578063248a9ca31461018b5780632f2ff15d146101c957806336568abe146101e957005b3661013457005b005b34801561014257600080fd5b5061015661015136600461143b565b6104b2565b60405190151581526020015b60405180910390f35b34801561017757600080fd5b50610134610186366004611481565b6104e9565b34801561019757600080fd5b506101bb6101a636600461149c565b60009081526020819052604090206001015490565b604051908152602001610162565b3480156101d557600080fd5b506101346101e43660046114b5565b610553565b3480156101f557600080fd5b506101346102043660046114b5565b61057d565b34801561021557600080fd5b506101346102243660046114e1565b610600565b34801561023557600080fd5b506101bb610244366004611514565b610835565b34801561025557600080fd5b50610134610264366004611566565b610bc6565b34801561027557600080fd5b50610134610284366004611481565b610d99565b34801561029557600080fd5b506101bb6102a436600461149c565b610e03565b3480156102b557600080fd5b506101346102c436600461162a565b610ef0565b3480156102d557600080fd5b506101566102e43660046114b5565b610fda565b3480156102f557600080fd5b506101bb600081565b34801561030a57600080fd5b5061031e610319366004611673565b611003565b6040805192835260ff909116602083015201610162565b34801561034157600080fd5b506101bb62278d0081565b34801561035857600080fd5b506101bb61036736600461169d565b611042565b34801561037857600080fd5b506101bb60025481565b34801561038e57600080fd5b5061013461039d3660046114b5565b611112565b3480156103ae57600080fd5b506101bb66038d7ea4c6800081565b3480156103c957600080fd5b506101bb6000805160206118ae83398151915281565b3480156103eb57600080fd5b506104406103fa36600461149c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610162565b34801561048857600080fd5b506101bb610497366004611481565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b14806104e357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206118ae83398151915261050181611137565b6105196000805160206118ae83398151915283611112565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461056e81611137565b6105788383611144565b505050565b6001600160a01b03811633146105f25760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105fc82826111c8565b5050565b6000805160206118ae83398151915261061881611137565b6000838152600160205260408120805490910361064857604051631b017f1760e11b815260040160405180910390fd5b80546002820154036106cc578281554260018201556002810183905560038101546040805185815260ff808416602083015261010084041691810191909152620100009091046001600160a01b03169085907f163d2dff0921e64458fa28a275a08ecb86f62058df960fcd1e199a61db8f8ddd9060600160405180910390a361082f565b66038d7ea4c68000816002015411156106f85760405163d4eff9fb60e01b815260040160405180910390fd5b60028101541561078457600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d806000811461075b576040519150601f19603f3d011682016040523d82523d6000602084013e610760565b606091505b505090508061078257604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906107b3908290610100900460ff166116dd565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a35b50505050565b60006000805160206118ae83398151915261084f81611137565b6001600160a01b038516600090815260036020908152604080832080548251818502810185019093528083528493849084015b828210156108c457600084815260209081902060408051808201909152600285029091018054825260019081015460ff16828401529083529092019101610882565b50505050905060005b81518110156109cb576000600160008484815181106108ee576108ee6116f6565b602090810291909101810151518252818101929092526040908101600020815160c081018352815481526001820154938101939093526002810154918301919091526003015460ff80821660608401819052610100830482166080850152620100009092046001600160a01b031660a084015291925090881690036109b857604081015181511461099257604051630644429360e01b815260040160405180910390fd5b8282815181106109a4576109a46116f6565b6020026020010151600001519350506109cb565b50806109c38161170c565b9150506108cd565b506000826000036109ef57600280549060006109e68361170c565b919050556109f1565b825b90506040518060c001604052808881526020014281526020018881526020018760ff168152602001600160ff168152602001896001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505082600003610b76576001600160a01b03881660008181526003602090815260408083208151808301835286815260ff8c81168286019081528354600180820186559488529686902092516002909702909201958655905194909101805460ff19169490911693909317909255905189815283917f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c910160405180910390a3610bbb565b876001600160a01b0316817f10fb48f0711b494fdbf819e97c500458db3e7873b7d01e20cc3084293f25191e89604051610bb291815260200190565b60405180910390a35b979650505050505050565b81471015610be75760405163a3fb8f9d60e01b815260040160405180910390fd5b60008381526001602052604081208054909103610c1757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b03163314610c4a576040516360b39bc560e01b815260040160405180910390fd5b6000610c5585610e03565b905083811015610c785760405163347efb5160e01b815260040160405180910390fd5b6000826001015442610c8a9190611725565b9050600082610c998784611738565b610ca3919061174f565b9050808460010154610cb59190611771565b846001018190555085846002016000828254610cd19190611725565b9091555050604051600090339088908381818185875af1925050503d8060008114610d18576040519150601f19603f3d011682016040523d82523d6000602084013e610d1d565b606091505b5050905080610d3f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610d87918b918b918e9160ff80831692610100900416906117d4565b60405180910390a25050505050505050565b6000805160206118ae833981519152610db181611137565b610dc96000805160206118ae83398151915283610553565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610e8557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610e9a5750600092915050565b6000816020015142610eac9190611725565b9050600062278d00828460000151610ec49190611738565b610ece919061174f565b905082604001518111610ee15780610ee7565b82604001515b95945050505050565b6000805160206118ae833981519152610f0881611137565b60008681526001602052604081208054909103610f3857604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6003602052816000526040600020818154811061101f57600080fd5b60009182526020909120600290910201805460019091015490925060ff16905082565b6000805b6001600160a01b038416600090815260036020526040902054811015611108576001600160a01b0384166000908152600360205260409020805460ff8516919083908110611096576110966116f6565b600091825260209091206001600290920201015460ff16036110f6576001600160a01b03841660009081526003602052604090208054829081106110dc576110dc6116f6565b9060005260206000209060020201600001549150506104e3565b806111008161170c565b915050611046565b5060009392505050565b60008281526020819052604090206001015461112d81611137565b61057883836111c8565b611141813361122d565b50565b61114e8282610fda565b6105fc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556111843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6111d28282610fda565b156105fc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6112378282610fda565b6105fc5761124481611286565b61124f836020611298565b60405160200161126092919061180e565b60408051601f198184030181529082905262461bcd60e51b82526105e991600401611883565b60606104e36001600160a01b03831660145b606060006112a7836002611738565b6112b2906002611771565b67ffffffffffffffff8111156112ca576112ca611550565b6040519080825280601f01601f1916602001820160405280156112f4576020820181803683370190505b509050600360fc1b8160008151811061130f5761130f6116f6565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061133e5761133e6116f6565b60200101906001600160f81b031916908160001a9053506000611362846002611738565b61136d906001611771565b90505b60018111156113e5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113a1576113a16116f6565b1a60f81b8282815181106113b7576113b76116f6565b60200101906001600160f81b031916908160001a90535060049490941c936113de81611896565b9050611370565b5083156114345760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105e9565b9392505050565b60006020828403121561144d57600080fd5b81356001600160e01b03198116811461143457600080fd5b80356001600160a01b038116811461147c57600080fd5b919050565b60006020828403121561149357600080fd5b61143482611465565b6000602082840312156114ae57600080fd5b5035919050565b600080604083850312156114c857600080fd5b823591506114d860208401611465565b90509250929050565b600080604083850312156114f457600080fd5b50508035926020909101359150565b803560ff8116811461147c57600080fd5b60008060006060848603121561152957600080fd5b61153284611465565b92506020840135915061154760408501611503565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561157b57600080fd5b8335925060208401359150604084013567ffffffffffffffff808211156115a157600080fd5b818601915086601f8301126115b557600080fd5b8135818111156115c7576115c7611550565b604051601f8201601f19908116603f011681019083821181831017156115ef576115ef611550565b8160405282815289602084870101111561160857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a0868803121561164257600080fd5b8535945060208601359350604086013592506060860135915061166760808701611503565b90509295509295909350565b6000806040838503121561168657600080fd5b61168f83611465565b946020939093013593505050565b600080604083850312156116b057600080fd5b6116b983611465565b91506114d860208401611503565b634e487b7160e01b600052601160045260246000fd5b60ff81811683821601908111156104e3576104e36116c7565b634e487b7160e01b600052603260045260246000fd5b60006001820161171e5761171e6116c7565b5060010190565b818103818111156104e3576104e36116c7565b80820281158282048414176104e3576104e36116c7565b60008261176c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156104e3576104e36116c7565b60005b8381101561179f578181015183820152602001611787565b50506000910152565b600081518084526117c0816020860160208601611784565b601f01601f19169290920160200192915050565b85815260a0602082015260006117ed60a08301876117a8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611846816017850160208801611784565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611877816028840160208801611784565b01602801949350505050565b60208152600061143460208301846117a8565b6000816118a5576118a56116c7565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220696172ba62ce09f5bf965770b353446ba592ec037821a87e4bd0133c062fe38564736f6c63430008110033", "devdoc": { "kind": "dev", "methods": { @@ -879,7 +975,7 @@ "type": "t_mapping(t_bytes32,t_struct(RoleData)19_storage)" }, { - "astId": 1514, + "astId": 1519, "contract": "contracts/Stream.sol:Stream", "label": "grantStreams", "offset": 0, @@ -887,7 +983,7 @@ "type": "t_mapping(t_uint256,t_struct(GrantStream)1509_storage)" }, { - "astId": 1517, + "astId": 1522, "contract": "contracts/Stream.sol:Stream", "label": "nextGrantId", "offset": 0, @@ -895,12 +991,12 @@ "type": "t_uint256" }, { - "astId": 1522, + "astId": 1528, "contract": "contracts/Stream.sol:Stream", "label": "builderGrants", "offset": 0, "slot": "3", - "type": "t_mapping(t_address,t_array(t_uint256)dyn_storage)" + "type": "t_mapping(t_address,t_array(t_struct(BuilderGrantData)1514_storage)dyn_storage)" } ], "types": { @@ -909,10 +1005,10 @@ "label": "address", "numberOfBytes": "20" }, - "t_array(t_uint256)dyn_storage": { - "base": "t_uint256", + "t_array(t_struct(BuilderGrantData)1514_storage)dyn_storage": { + "base": "t_struct(BuilderGrantData)1514_storage", "encoding": "dynamic_array", - "label": "uint256[]", + "label": "struct Stream.BuilderGrantData[]", "numberOfBytes": "32" }, "t_bool": { @@ -925,12 +1021,12 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_mapping(t_address,t_array(t_uint256)dyn_storage)": { + "t_mapping(t_address,t_array(t_struct(BuilderGrantData)1514_storage)dyn_storage)": { "encoding": "mapping", "key": "t_address", - "label": "mapping(address => uint256[])", + "label": "mapping(address => struct Stream.BuilderGrantData[])", "numberOfBytes": "32", - "value": "t_array(t_uint256)dyn_storage" + "value": "t_array(t_struct(BuilderGrantData)1514_storage)dyn_storage" }, "t_mapping(t_address,t_bool)": { "encoding": "mapping", @@ -953,6 +1049,29 @@ "numberOfBytes": "32", "value": "t_struct(GrantStream)1509_storage" }, + "t_struct(BuilderGrantData)1514_storage": { + "encoding": "inplace", + "label": "struct Stream.BuilderGrantData", + "members": [ + { + "astId": 1511, + "contract": "contracts/Stream.sol:Stream", + "label": "grantId", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 1513, + "contract": "contracts/Stream.sol:Stream", + "label": "grantNumber", + "offset": 0, + "slot": "1", + "type": "t_uint8" + } + ], + "numberOfBytes": "64" + }, "t_struct(GrantStream)1509_storage": { "encoding": "inplace", "label": "struct Stream.GrantStream", diff --git a/packages/hardhat/deployments/optimism/solcInputs/12a05f03603bc9679d7744afc23e7a9f.json b/packages/hardhat/deployments/optimism/solcInputs/9678b3902dbd92493a7cc9d28ddcf484.json similarity index 79% rename from packages/hardhat/deployments/optimism/solcInputs/12a05f03603bc9679d7744afc23e7a9f.json rename to packages/hardhat/deployments/optimism/solcInputs/9678b3902dbd92493a7cc9d28ddcf484.json index 6956df6..f7aac51 100644 --- a/packages/hardhat/deployments/optimism/solcInputs/12a05f03603bc9679d7744afc23e7a9f.json +++ b/packages/hardhat/deployments/optimism/solcInputs/9678b3902dbd92493a7cc9d28ddcf484.json @@ -23,7 +23,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "contracts/Stream.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ncontract Stream is AccessControl {\n\tbytes32 public constant OWNER_ROLE = keccak256(\"OWNER_ROLE\");\n\n\tstruct GrantStream {\n\t\tuint256 cap;\n\t\tuint256 last;\n\t\tuint256 amountLeft;\n\t\tuint8 grantNumber;\n\t\tuint8 stageNumber;\n\t\taddress builder;\n\t}\n\n\tmapping(uint256 => GrantStream) public grantStreams;\n\tuint256 public nextGrantId = 1;\n\n\tmapping(address => uint256[]) public builderGrants;\n\n\t// uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 3 minutes\n\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days\n\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\n\n\tevent Withdraw(\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tstring reason,\n\t\tuint256 grantId,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\n\tevent MoveGrantToNextStage(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent UpdateGrant(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 cap,\n\t\tuint256 last,\n\t\tuint256 amountLeft,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddOwner(address indexed newOwner, address indexed addedBy);\n\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\n\n\t// Custom errors\n\terror NoActiveStream();\n\terror InsufficientContractFunds();\n\terror UnauthorizedWithdrawal();\n\terror InsufficientStreamFunds();\n\terror FailedToSendEther();\n\terror PreviousAmountNotFullyWithdrawn();\n\n\tconstructor(address[] memory _initialOwners) {\n\t\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\n\t\tfor (uint i = 0; i < _initialOwners.length; i++) {\n\t\t\t_grantRole(OWNER_ROLE, _initialOwners[i]);\n\t\t}\n\t}\n\n\tfunction unlockedGrantAmount(\n\t\tuint256 _grantId\n\t) public view returns (uint256) {\n\t\tGrantStream memory grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft == 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\n\t\t\tFULL_STREAM_UNLOCK_PERIOD;\n\n\t\treturn\n\t\t\tunlockedAmount > grantStream.amountLeft\n\t\t\t\t? grantStream.amountLeft\n\t\t\t\t: unlockedAmount;\n\t}\n\n\tfunction addGrantStream(\n\t\taddress _builder,\n\t\tuint256 _cap,\n\t\tuint8 _grantNumber\n\t) public onlyRole(OWNER_ROLE) returns (uint256) {\n\t\tuint256 grantId = nextGrantId++;\n\t\tgrantStreams[grantId] = GrantStream({\n\t\t\tcap: _cap,\n\t\t\tlast: block.timestamp,\n\t\t\tamountLeft: _cap,\n\t\t\tgrantNumber: _grantNumber,\n\t\t\tstageNumber: 1,\n\t\t\tbuilder: _builder\n\t\t});\n\t\tbuilderGrants[_builder].push(grantId);\n\t\temit AddGrant(grantId, _builder, _cap);\n\t\treturn grantId;\n\t}\n\n\tfunction moveGrantToNextStage(\n\t\tuint256 _grantId,\n\t\tuint256 _cap\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft > DUST_THRESHOLD)\n\t\t\trevert PreviousAmountNotFullyWithdrawn();\n\n\t\tif (grantStream.amountLeft > 0) {\n\t\t\t(bool sent, ) = payable(grantStream.builder).call{\n\t\t\t\tvalue: grantStream.amountLeft\n\t\t\t}(\"\");\n\t\t\tif (!sent) revert FailedToSendEther();\n\t\t}\n\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = block.timestamp;\n\t\tgrantStream.amountLeft = _cap;\n\t\tgrantStream.stageNumber += 1;\n\n\t\temit MoveGrantToNextStage(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction updateGrant(\n\t\tuint256 _grantId,\n\t\tuint256 _cap,\n\t\tuint256 _last,\n\t\tuint256 _amountLeft,\n\t\tuint8 _stageNumber\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = _last;\n\t\tgrantStream.amountLeft = _amountLeft;\n\t\tgrantStream.stageNumber = _stageNumber;\n\n\t\temit UpdateGrant(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.last,\n\t\t\tgrantStream.amountLeft,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction streamWithdraw(\n\t\tuint256 _grantId,\n\t\tuint256 _amount,\n\t\tstring memory _reason\n\t) public {\n\t\tif (address(this).balance < _amount) revert InsufficientContractFunds();\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\n\n\t\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\n\t\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\n\n\t\tgrantStream.last = grantStream.last + timeToDeduct;\n\t\tgrantStream.amountLeft -= _amount;\n\n\t\t(bool sent, ) = msg.sender.call{ value: _amount }(\"\");\n\t\tif (!sent) revert FailedToSendEther();\n\n\t\temit Withdraw(\n\t\t\tmsg.sender,\n\t\t\t_amount,\n\t\t\t_reason,\n\t\t\t_grantId,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction getBuilderGrantCount(\n\t\taddress _builder\n\t) public view returns (uint256) {\n\t\treturn builderGrants[_builder].length;\n\t}\n\n\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\n\t\tgrantRole(OWNER_ROLE, newOwner);\n\t\temit AddOwner(newOwner, msg.sender);\n\t}\n\n\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\n\t\trevokeRole(OWNER_ROLE, owner);\n\t\temit RemoveOwner(owner, msg.sender);\n\t}\n\n\treceive() external payable {}\n\n\tfallback() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ncontract Stream is AccessControl {\n\tbytes32 public constant OWNER_ROLE = keccak256(\"OWNER_ROLE\");\n\n\tstruct GrantStream {\n\t\tuint256 cap;\n\t\tuint256 last;\n\t\tuint256 amountLeft;\n\t\tuint8 grantNumber;\n\t\tuint8 stageNumber;\n\t\taddress builder;\n\t}\n\n\tstruct BuilderGrantData {\n\t\tuint256 grantId;\n\t\tuint8 grantNumber;\n\t}\n\n\tmapping(uint256 => GrantStream) public grantStreams;\n\tuint256 public nextGrantId = 1;\n\n\tmapping(address => BuilderGrantData[]) public builderGrants;\n\n\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days\n\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\n\n\tevent Withdraw(\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tstring reason,\n\t\tuint256 grantId,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\n\tevent ReinitializeGrant(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 amount\n\t);\n\tevent MoveGrantToNextStage(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent ReinitializeNextStage(\n\t\tuint256 indexed grantId,\n\t\taddress indexed builder,\n\t\tuint256 amount,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent UpdateGrant(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 cap,\n\t\tuint256 last,\n\t\tuint256 amountLeft,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddOwner(address indexed newOwner, address indexed addedBy);\n\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\n\n\t// Custom errors\n\terror NoActiveStream();\n\terror InsufficientContractFunds();\n\terror UnauthorizedWithdrawal();\n\terror InsufficientStreamFunds();\n\terror FailedToSendEther();\n\terror PreviousAmountNotFullyWithdrawn();\n\terror AlreadyWithdrawnFromGrant();\n\n\tconstructor(address[] memory _initialOwners) {\n\t\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\n\t\tfor (uint i = 0; i < _initialOwners.length; i++) {\n\t\t\t_grantRole(OWNER_ROLE, _initialOwners[i]);\n\t\t}\n\t}\n\n\tfunction unlockedGrantAmount(\n\t\tuint256 _grantId\n\t) public view returns (uint256) {\n\t\tGrantStream memory grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft == 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\n\t\t\tFULL_STREAM_UNLOCK_PERIOD;\n\n\t\treturn\n\t\t\tunlockedAmount > grantStream.amountLeft\n\t\t\t\t? grantStream.amountLeft\n\t\t\t\t: unlockedAmount;\n\t}\n\n\tfunction addGrantStream(\n\t\taddress _builder,\n\t\tuint256 _cap,\n\t\tuint8 _grantNumber\n\t) public onlyRole(OWNER_ROLE) returns (uint256) {\n\t\t// check if grantStream with same grantNumber already exists\n\t\tuint256 existingGrantId;\n\t\tBuilderGrantData[] memory existingBuilderGrants = builderGrants[\n\t\t\t_builder\n\t\t];\n\t\tfor (uint i = 0; i < existingBuilderGrants.length; i++) {\n\t\t\tGrantStream memory existingGrant = grantStreams[\n\t\t\t\texistingBuilderGrants[i].grantId\n\t\t\t];\n\t\t\tif (existingGrant.grantNumber == _grantNumber) {\n\t\t\t\tif (existingGrant.cap != existingGrant.amountLeft) {\n\t\t\t\t\trevert AlreadyWithdrawnFromGrant();\n\t\t\t\t}\n\t\t\t\texistingGrantId = existingBuilderGrants[i].grantId;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// update existing grant or create new one\n\t\tuint256 grantId = existingGrantId != 0\n\t\t\t? existingGrantId\n\t\t\t: nextGrantId++;\n\n\t\tgrantStreams[grantId] = GrantStream({\n\t\t\tcap: _cap,\n\t\t\tlast: block.timestamp,\n\t\t\tamountLeft: _cap,\n\t\t\tgrantNumber: _grantNumber,\n\t\t\tstageNumber: 1,\n\t\t\tbuilder: _builder\n\t\t});\n\n\t\tif (existingGrantId == 0) {\n\t\t\tbuilderGrants[_builder].push(\n\t\t\t\tBuilderGrantData({\n\t\t\t\t\tgrantId: grantId,\n\t\t\t\t\tgrantNumber: _grantNumber\n\t\t\t\t})\n\t\t\t);\n\t\t\temit AddGrant(grantId, _builder, _cap);\n\t\t} else {\n\t\t\temit ReinitializeGrant(grantId, _builder, _cap);\n\t\t}\n\t\treturn grantId;\n\t}\n\n\tfunction moveGrantToNextStage(\n\t\tuint256 _grantId,\n\t\tuint256 _cap\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\t// If amountLeft equals cap, reinitialize with same stage number\n\t\tif (grantStream.amountLeft == grantStream.cap) {\n\t\t\tgrantStream.cap = _cap;\n\t\t\tgrantStream.last = block.timestamp;\n\t\t\tgrantStream.amountLeft = _cap;\n\t\t\t// Stage number remains the same\n\t\t\temit ReinitializeNextStage(\n\t\t\t\t_grantId,\n\t\t\t\tgrantStream.builder,\n\t\t\t\t_cap,\n\t\t\t\tgrantStream.grantNumber,\n\t\t\t\tgrantStream.stageNumber\n\t\t\t);\n\t\t} else {\n\t\t\tif (grantStream.amountLeft > DUST_THRESHOLD)\n\t\t\t\trevert PreviousAmountNotFullyWithdrawn();\n\n\t\t\tif (grantStream.amountLeft > 0) {\n\t\t\t\t(bool sent, ) = payable(grantStream.builder).call{\n\t\t\t\t\tvalue: grantStream.amountLeft\n\t\t\t\t}(\"\");\n\t\t\t\tif (!sent) revert FailedToSendEther();\n\t\t\t}\n\n\t\t\tgrantStream.cap = _cap;\n\t\t\tgrantStream.last = block.timestamp;\n\t\t\tgrantStream.amountLeft = _cap;\n\t\t\tgrantStream.stageNumber += 1;\n\n\t\t\temit MoveGrantToNextStage(\n\t\t\t\t_grantId,\n\t\t\t\tgrantStream.builder,\n\t\t\t\t_cap,\n\t\t\t\tgrantStream.grantNumber,\n\t\t\t\tgrantStream.stageNumber\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction updateGrant(\n\t\tuint256 _grantId,\n\t\tuint256 _cap,\n\t\tuint256 _last,\n\t\tuint256 _amountLeft,\n\t\tuint8 _stageNumber\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = _last;\n\t\tgrantStream.amountLeft = _amountLeft;\n\t\tgrantStream.stageNumber = _stageNumber;\n\n\t\temit UpdateGrant(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.last,\n\t\t\tgrantStream.amountLeft,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction streamWithdraw(\n\t\tuint256 _grantId,\n\t\tuint256 _amount,\n\t\tstring memory _reason\n\t) public {\n\t\tif (address(this).balance < _amount) revert InsufficientContractFunds();\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\n\n\t\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\n\t\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\n\n\t\tgrantStream.last = grantStream.last + timeToDeduct;\n\t\tgrantStream.amountLeft -= _amount;\n\n\t\t(bool sent, ) = msg.sender.call{ value: _amount }(\"\");\n\t\tif (!sent) revert FailedToSendEther();\n\n\t\temit Withdraw(\n\t\t\tmsg.sender,\n\t\t\t_amount,\n\t\t\t_reason,\n\t\t\t_grantId,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction getBuilderGrantCount(\n\t\taddress _builder\n\t) public view returns (uint256) {\n\t\treturn builderGrants[_builder].length;\n\t}\n\n\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\n\t\tgrantRole(OWNER_ROLE, newOwner);\n\t\temit AddOwner(newOwner, msg.sender);\n\t}\n\n\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\n\t\trevokeRole(OWNER_ROLE, owner);\n\t\temit RemoveOwner(owner, msg.sender);\n\t}\n\n\tfunction getGrantIdByBuilderAndGrantNumber(\n\t\taddress _builder,\n\t\tuint8 _grantNumber\n\t) public view returns (uint256) {\n\t\tfor (uint256 i = 0; i < builderGrants[_builder].length; i++) {\n\t\t\tif (builderGrants[_builder][i].grantNumber == _grantNumber) {\n\t\t\t\treturn builderGrants[_builder][i].grantId;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\treceive() external payable {}\n\n\tfallback() external payable {}\n}\n" } }, "settings": { diff --git a/packages/nextjs/.env.development b/packages/nextjs/.env.development deleted file mode 100644 index f4bf444..0000000 --- a/packages/nextjs/.env.development +++ /dev/null @@ -1,3 +0,0 @@ -POSTGRES_URL="postgresql://postgres:mysecretpassword@localhost:5432/postgres" -NEXTAUTH_URL=http://localhost:3000 -NEXTAUTH_SECRET=somereallysecretsecret diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index d6ca018..268bc2d 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -5,6 +5,850 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { + 10: { + Stream: { + address: "0x72704F28704fe9dF50516e0Fc29FbD9261a3DE64", + abi: [ + { + inputs: [ + { + internalType: "address[]", + name: "_initialOwners", + type: "address[]", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "AlreadyWithdrawnFromGrant", + type: "error", + }, + { + inputs: [], + name: "FailedToSendEther", + type: "error", + }, + { + inputs: [], + name: "InsufficientContractFunds", + type: "error", + }, + { + inputs: [], + name: "InsufficientStreamFunds", + type: "error", + }, + { + inputs: [], + name: "NoActiveStream", + type: "error", + }, + { + inputs: [], + name: "PreviousAmountNotFullyWithdrawn", + type: "error", + }, + { + inputs: [], + name: "UnauthorizedWithdrawal", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "AddGrant", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "addedBy", + type: "address", + }, + ], + name: "AddOwner", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + indexed: false, + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + ], + name: "MoveGrantToNextStage", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "ReinitializeGrant", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "builder", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + indexed: false, + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + ], + name: "ReinitializeNextStage", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "removedOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "removedBy", + type: "address", + }, + ], + name: "RemoveOwner", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "previousAdminRole", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "newAdminRole", + type: "bytes32", + }, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleRevoked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "cap", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "last", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "amountLeft", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + indexed: false, + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + ], + name: "UpdateGrant", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "reason", + type: "string", + }, + { + indexed: false, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + indexed: false, + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + ], + name: "Withdraw", + type: "event", + }, + { + stateMutability: "payable", + type: "fallback", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DUST_THRESHOLD", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "FULL_STREAM_UNLOCK_PERIOD", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "OWNER_ROLE", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_builder", + type: "address", + }, + { + internalType: "uint256", + name: "_cap", + type: "uint256", + }, + { + internalType: "uint8", + name: "_grantNumber", + type: "uint8", + }, + ], + name: "addGrantStream", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "addOwner", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "builderGrants", + outputs: [ + { + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_builder", + type: "address", + }, + ], + name: "getBuilderGrantCount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_builder", + type: "address", + }, + { + internalType: "uint8", + name: "_grantNumber", + type: "uint8", + }, + ], + name: "getGrantIdByBuilderAndGrantNumber", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + ], + name: "getRoleAdmin", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "grantStreams", + outputs: [ + { + internalType: "uint256", + name: "cap", + type: "uint256", + }, + { + internalType: "uint256", + name: "last", + type: "uint256", + }, + { + internalType: "uint256", + name: "amountLeft", + type: "uint256", + }, + { + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + { + internalType: "address", + name: "builder", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "hasRole", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_grantId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_cap", + type: "uint256", + }, + ], + name: "moveGrantToNextStage", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "nextGrantId", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "removeOwner", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_grantId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + { + internalType: "string", + name: "_reason", + type: "string", + }, + ], + name: "streamWithdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes4", + name: "interfaceId", + type: "bytes4", + }, + ], + name: "supportsInterface", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_grantId", + type: "uint256", + }, + ], + name: "unlockedGrantAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_grantId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_cap", + type: "uint256", + }, + { + internalType: "uint256", + name: "_last", + type: "uint256", + }, + { + internalType: "uint256", + name: "_amountLeft", + type: "uint256", + }, + { + internalType: "uint8", + name: "_stageNumber", + type: "uint8", + }, + ], + name: "updateGrant", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, + ], + inheritedFunctions: { + DEFAULT_ADMIN_ROLE: "@openzeppelin/contracts/access/AccessControl.sol", + getRoleAdmin: "@openzeppelin/contracts/access/AccessControl.sol", + grantRole: "@openzeppelin/contracts/access/AccessControl.sol", + hasRole: "@openzeppelin/contracts/access/AccessControl.sol", + renounceRole: "@openzeppelin/contracts/access/AccessControl.sol", + revokeRole: "@openzeppelin/contracts/access/AccessControl.sol", + supportsInterface: "@openzeppelin/contracts/access/AccessControl.sol", + }, + }, + }, 31337: { Stream: { address: "0x5FbDB2315678afecb367f032d93F642f64180aa3", @@ -20,6 +864,11 @@ const deployedContracts = { stateMutability: "nonpayable", type: "constructor", }, + { + inputs: [], + name: "AlreadyWithdrawnFromGrant", + type: "error", + }, { inputs: [], name: "FailedToSendEther", @@ -131,6 +980,68 @@ const deployedContracts = { name: "MoveGrantToNextStage", type: "event", }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "ReinitializeGrant", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "grantId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "builder", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint8", + name: "grantNumber", + type: "uint8", + }, + { + indexed: false, + internalType: "uint8", + name: "stageNumber", + type: "uint8", + }, + ], + name: "ReinitializeNextStage", + type: "event", + }, { anonymous: false, inputs: [ diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index c3362ea..1ab151a 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -12,7 +12,7 @@ export type ScaffoldConfig = { const scaffoldConfig = { // The networks on which your DApp is live - targetNetworks: [chains.hardhat], + targetNetworks: [chains.optimism], // The interval at which your front-end polls the RPC servers for new data // it has no effect if you only target the local network (default is 4000) @@ -37,7 +37,7 @@ const scaffoldConfig = { disableBurnerWalletOnLocal: true, // start blocknumber for contract deployment indexing - startBlock: 0, + startBlock: 128564237, } as const satisfies ScaffoldConfig; export default scaffoldConfig; From 77d3da7f4d1ce714b2c9c9f2b8d1bcb64cb58de9 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 27 Nov 2024 22:59:59 +0530 Subject: [PATCH 8/8] remove sepolia deployment --- packages/hardhat/deployments/sepolia/.chainId | 1 - .../hardhat/deployments/sepolia/Stream.json | 1046 ----------- .../66949c7747c59450b1528b6c03e97e3b.json | 56 - .../nextjs/contracts/deployedContracts.ts | 1592 ----------------- 4 files changed, 2695 deletions(-) delete mode 100644 packages/hardhat/deployments/sepolia/.chainId delete mode 100644 packages/hardhat/deployments/sepolia/Stream.json delete mode 100644 packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json diff --git a/packages/hardhat/deployments/sepolia/.chainId b/packages/hardhat/deployments/sepolia/.chainId deleted file mode 100644 index 1b14418..0000000 --- a/packages/hardhat/deployments/sepolia/.chainId +++ /dev/null @@ -1 +0,0 @@ -11155111 diff --git a/packages/hardhat/deployments/sepolia/Stream.json b/packages/hardhat/deployments/sepolia/Stream.json deleted file mode 100644 index fb578a6..0000000 --- a/packages/hardhat/deployments/sepolia/Stream.json +++ /dev/null @@ -1,1046 +0,0 @@ -{ - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "abi": [ - { - "inputs": [ - { - "internalType": "address[]", - "name": "_initialOwners", - "type": "address[]" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "FailedToSendEther", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientContractFunds", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientStreamFunds", - "type": "error" - }, - { - "inputs": [], - "name": "NoActiveStream", - "type": "error" - }, - { - "inputs": [], - "name": "PreviousAmountNotFullyWithdrawn", - "type": "error" - }, - { - "inputs": [], - "name": "UnauthorizedWithdrawal", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "grantId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "AddGrant", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "addedBy", - "type": "address" - } - ], - "name": "AddOwner", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "grantId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "grantNumber", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "stageNumber", - "type": "uint8" - } - ], - "name": "MoveGrantToNextStage", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "removedOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "removedBy", - "type": "address" - } - ], - "name": "RemoveOwner", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } - ], - "name": "RoleAdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleGranted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleRevoked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "grantId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "cap", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "last", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountLeft", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "grantNumber", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "stageNumber", - "type": "uint8" - } - ], - "name": "UpdateGrant", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "reason", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "grantId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "grantNumber", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "stageNumber", - "type": "uint8" - } - ], - "name": "Withdraw", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "DUST_THRESHOLD", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "FULL_STREAM_UNLOCK_PERIOD", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "OWNER_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_builder", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_cap", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "_grantNumber", - "type": "uint8" - } - ], - "name": "addGrantStream", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "addOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "builderGrants", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_builder", - "type": "address" - } - ], - "name": "getBuilderGrantCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], - "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "grantStreams", - "outputs": [ - { - "internalType": "uint256", - "name": "cap", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "last", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountLeft", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "grantNumber", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "stageNumber", - "type": "uint8" - }, - { - "internalType": "address", - "name": "builder", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_grantId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_cap", - "type": "uint256" - } - ], - "name": "moveGrantToNextStage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "nextGrantId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "removeOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_grantId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_reason", - "type": "string" - } - ], - "name": "streamWithdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_grantId", - "type": "uint256" - } - ], - "name": "unlockedGrantAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_grantId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_cap", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_last", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_amountLeft", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "_stageNumber", - "type": "uint8" - } - ], - "name": "updateGrant", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "receipt": { - "to": null, - "from": "0x55b9CB0bCf56057010b9c471e7D42d60e1111EEa", - "contractAddress": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "transactionIndex": 31, - "gasUsed": "1389401", - "logsBloom": "0x0000000400000000080000000000000008008000000000000002000000000000000000000000000000000100000000000000000000000000000000000050000040000000000000000000000000100000000000000000000000000000000000000000000002000c400000020000000800000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000001000000000000020000000000000000000000000000000000000000000000100000000000020000000001000000000000000000000001000000000000000000000000008002000", - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f", - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "logs": [ - { - "transactionIndex": 31, - "blockNumber": 6641664, - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "topics": [ - "0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e" - ], - "data": "0x", - "logIndex": 64, - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" - }, - { - "transactionIndex": 31, - "blockNumber": 6641664, - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "topics": [ - "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea", - "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" - ], - "data": "0x", - "logIndex": 65, - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" - }, - { - "transactionIndex": 31, - "blockNumber": 6641664, - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "topics": [ - "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "0x00000000000000000000000060583563d5879c2e59973e5718c7de2147971807", - "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" - ], - "data": "0x", - "logIndex": 66, - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" - }, - { - "transactionIndex": 31, - "blockNumber": 6641664, - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "topics": [ - "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "0x000000000000000000000000b8224dfcf3c174331a8e6a841aeea7df321f6d8e", - "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" - ], - "data": "0x", - "logIndex": 67, - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" - }, - { - "transactionIndex": 31, - "blockNumber": 6641664, - "transactionHash": "0xbb155808c08414941008c1c8219caf1721f9f495d62e8477ab4d769a9d339ad0", - "address": "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - "topics": [ - "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", - "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "0x000000000000000000000000b4f53bd85c00ef22946d24ae26bc38ac64f5e7b1", - "0x00000000000000000000000055b9cb0bcf56057010b9c471e7d42d60e1111eea" - ], - "data": "0x", - "logIndex": 68, - "blockHash": "0xe8eeb9d367a52f8e984cbd69fb1dce4f2f8222d64d218121b1f12d0aae54493f" - } - ], - "blockNumber": 6641664, - "cumulativeGasUsed": "6982808", - "status": 1, - "byzantium": true - }, - "args": [ - [ - "0x55b9CB0bCf56057010b9c471e7D42d60e1111EEa", - "0x60583563D5879C2E59973E5718c7DE2147971807", - "0xb8224dfCf3C174331a8e6a841AEEa7dF321f6D8E", - "0xB4F53bd85c00EF22946d24Ae26BC38Ac64F5E7B1" - ] - ], - "numDeployments": 1, - "solcInputHash": "66949c7747c59450b1528b6c03e97e3b", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_initialOwners\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientContractFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientStreamFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoActiveStream\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PreviousAmountNotFullyWithdrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AddGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addedBy\",\"type\":\"address\"}],\"name\":\"AddOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"MoveGrantToNextStage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"removedBy\",\"type\":\"address\"}],\"name\":\"RemoveOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"UpdateGrant\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"grantId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DUST_THRESHOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_STREAM_UNLOCK_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OWNER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_grantNumber\",\"type\":\"uint8\"}],\"name\":\"addGrantStream\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"addOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"builderGrants\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_builder\",\"type\":\"address\"}],\"name\":\"getBuilderGrantCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantStreams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"grantNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"stageNumber\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"}],\"name\":\"moveGrantToNextStage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextGrantId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"removeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"streamWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"}],\"name\":\"unlockedGrantAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_grantId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_last\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amountLeft\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"_stageNumber\",\"type\":\"uint8\"}],\"name\":\"updateGrant\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Stream.sol\":\"Stream\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => RoleData) private _roles;\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\\n * Overriding this function changes the behavior of the {onlyRole} modifier.\\n *\\n * Format of the revert message is described in {_checkRole}.\\n *\\n * _Available since v4.6._\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(account),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\\n return _roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * May emit a {RoleGranted} event.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n _roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67e3daf189111d6d5b0464ed09cf9f0605a22c4b965a7fcecd707101faff008a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/Stream.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\n\\ncontract Stream is AccessControl {\\n\\tbytes32 public constant OWNER_ROLE = keccak256(\\\"OWNER_ROLE\\\");\\n\\n\\tstruct GrantStream {\\n\\t\\tuint256 cap;\\n\\t\\tuint256 last;\\n\\t\\tuint256 amountLeft;\\n\\t\\tuint8 grantNumber;\\n\\t\\tuint8 stageNumber;\\n\\t\\taddress builder;\\n\\t}\\n\\n\\tmapping(uint256 => GrantStream) public grantStreams;\\n\\tuint256 public nextGrantId = 1;\\n\\n\\tmapping(address => uint256[]) public builderGrants;\\n\\n\\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 30 days\\n\\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\\n\\n\\tevent Withdraw(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tstring reason,\\n\\t\\tuint256 grantId,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\\n\\tevent MoveGrantToNextStage(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 amount,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent UpdateGrant(\\n\\t\\tuint256 indexed grantId,\\n\\t\\taddress indexed to,\\n\\t\\tuint256 cap,\\n\\t\\tuint256 last,\\n\\t\\tuint256 amountLeft,\\n\\t\\tuint8 grantNumber,\\n\\t\\tuint8 stageNumber\\n\\t);\\n\\tevent AddOwner(address indexed newOwner, address indexed addedBy);\\n\\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\\n\\n\\t// Custom errors\\n\\terror NoActiveStream();\\n\\terror InsufficientContractFunds();\\n\\terror UnauthorizedWithdrawal();\\n\\terror InsufficientStreamFunds();\\n\\terror FailedToSendEther();\\n\\terror PreviousAmountNotFullyWithdrawn();\\n\\n\\tconstructor(address[] memory _initialOwners) {\\n\\t\\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\\n\\t\\tfor (uint i = 0; i < _initialOwners.length; i++) {\\n\\t\\t\\t_grantRole(OWNER_ROLE, _initialOwners[i]);\\n\\t\\t}\\n\\t}\\n\\n\\tfunction unlockedGrantAmount(\\n\\t\\tuint256 _grantId\\n\\t) public view returns (uint256) {\\n\\t\\tGrantStream memory grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft == 0) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\\n\\t\\t\\tFULL_STREAM_UNLOCK_PERIOD;\\n\\n\\t\\treturn\\n\\t\\t\\tunlockedAmount > grantStream.amountLeft\\n\\t\\t\\t\\t? grantStream.amountLeft\\n\\t\\t\\t\\t: unlockedAmount;\\n\\t}\\n\\n\\tfunction addGrantStream(\\n\\t\\taddress _builder,\\n\\t\\tuint256 _cap,\\n\\t\\tuint8 _grantNumber\\n\\t) public onlyRole(OWNER_ROLE) returns (uint256) {\\n\\t\\tuint256 grantId = nextGrantId++;\\n\\t\\tgrantStreams[grantId] = GrantStream({\\n\\t\\t\\tcap: _cap,\\n\\t\\t\\tlast: block.timestamp,\\n\\t\\t\\tamountLeft: _cap,\\n\\t\\t\\tgrantNumber: _grantNumber,\\n\\t\\t\\tstageNumber: 1,\\n\\t\\t\\tbuilder: _builder\\n\\t\\t});\\n\\t\\tbuilderGrants[_builder].push(grantId);\\n\\t\\temit AddGrant(grantId, _builder, _cap);\\n\\t\\treturn grantId;\\n\\t}\\n\\n\\tfunction moveGrantToNextStage(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\n\\t\\tif (grantStream.amountLeft > DUST_THRESHOLD)\\n\\t\\t\\trevert PreviousAmountNotFullyWithdrawn();\\n\\n\\t\\tif (grantStream.amountLeft > 0) {\\n\\t\\t\\t(bool sent, ) = payable(grantStream.builder).call{\\n\\t\\t\\t\\tvalue: grantStream.amountLeft\\n\\t\\t\\t}(\\\"\\\");\\n\\t\\t\\tif (!sent) revert FailedToSendEther();\\n\\t\\t}\\n\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = block.timestamp;\\n\\t\\tgrantStream.amountLeft = _cap;\\n\\t\\tgrantStream.stageNumber += 1;\\n\\n\\t\\temit MoveGrantToNextStage(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction updateGrant(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _cap,\\n\\t\\tuint256 _last,\\n\\t\\tuint256 _amountLeft,\\n\\t\\tuint8 _stageNumber\\n\\t) public onlyRole(OWNER_ROLE) {\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tgrantStream.cap = _cap;\\n\\t\\tgrantStream.last = _last;\\n\\t\\tgrantStream.amountLeft = _amountLeft;\\n\\t\\tgrantStream.stageNumber = _stageNumber;\\n\\n\\t\\temit UpdateGrant(\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.builder,\\n\\t\\t\\t_cap,\\n\\t\\t\\tgrantStream.last,\\n\\t\\t\\tgrantStream.amountLeft,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction streamWithdraw(\\n\\t\\tuint256 _grantId,\\n\\t\\tuint256 _amount,\\n\\t\\tstring memory _reason\\n\\t) public {\\n\\t\\tif (address(this).balance < _amount) revert InsufficientContractFunds();\\n\\t\\tGrantStream storage grantStream = grantStreams[_grantId];\\n\\t\\tif (grantStream.cap == 0) revert NoActiveStream();\\n\\t\\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\\n\\n\\t\\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\\n\\t\\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\\n\\n\\t\\tuint256 elapsedTime = block.timestamp - grantStream.last;\\n\\t\\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\\n\\n\\t\\tgrantStream.last = grantStream.last + timeToDeduct;\\n\\t\\tgrantStream.amountLeft -= _amount;\\n\\n\\t\\t(bool sent, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n\\t\\tif (!sent) revert FailedToSendEther();\\n\\n\\t\\temit Withdraw(\\n\\t\\t\\tmsg.sender,\\n\\t\\t\\t_amount,\\n\\t\\t\\t_reason,\\n\\t\\t\\t_grantId,\\n\\t\\t\\tgrantStream.grantNumber,\\n\\t\\t\\tgrantStream.stageNumber\\n\\t\\t);\\n\\t}\\n\\n\\tfunction getBuilderGrantCount(\\n\\t\\taddress _builder\\n\\t) public view returns (uint256) {\\n\\t\\treturn builderGrants[_builder].length;\\n\\t}\\n\\n\\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\\n\\t\\tgrantRole(OWNER_ROLE, newOwner);\\n\\t\\temit AddOwner(newOwner, msg.sender);\\n\\t}\\n\\n\\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\\n\\t\\trevokeRole(OWNER_ROLE, owner);\\n\\t\\temit RemoveOwner(owner, msg.sender);\\n\\t}\\n\\n\\treceive() external payable {}\\n\\n\\tfallback() external payable {}\\n}\\n\",\"keccak256\":\"0xf5915a4a9feb7db4b58cdd9de70ceab466c11d75769d2596452336c6f75b62ce\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405260016002553480156200001657600080fd5b5060405162001863380380620018638339810160408190526200003991620001da565b620000546000805160206200184383398151915280620000bb565b60005b8151811015620000b3576200009e600080516020620018438339815191528383815181106200008a576200008a620002ac565b60200260200101516200010660201b60201c565b80620000aa81620002c2565b91505062000057565b5050620002ea565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001a3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620001d557600080fd5b919050565b60006020808385031215620001ee57600080fd5b82516001600160401b03808211156200020657600080fd5b818501915085601f8301126200021b57600080fd5b815181811115620002305762000230620001a7565b8060051b604051601f19603f83011681018181108582111715620002585762000258620001a7565b6040529182528482019250838101850191888311156200027757600080fd5b938501935b82851015620002a0576200029085620001bd565b845293850193928501926200027c565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620002e357634e487b7160e01b600052601160045260246000fd5b5060010190565b61154980620002fa6000396000f3fe6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea914610328578063d547741f1461033e578063dd7dc9a91461035e578063e58378bb14610379578063ed2c9d091461039b578063f1f693d11461043857005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110ab565b61046e565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f1565b6104a5565b34801561018c57600080fd5b506101b061019b36600461110c565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611125565b61050f565b3480156101ea57600080fd5b506101296101f9366004611125565b610539565b34801561020a57600080fd5b50610129610219366004611151565b6105bc565b34801561022a57600080fd5b506101b0610239366004611184565b61076c565b34801561024a57600080fd5b506101296102593660046111d6565b610916565b34801561026a57600080fd5b506101296102793660046110f1565b610ae9565b34801561028a57600080fd5b506101b061029936600461110c565b610b53565b3480156102aa57600080fd5b506101296102b936600461129a565b610c3e565b3480156102ca57600080fd5b5061014b6102d9366004611125565b610d28565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e3565b610d51565b34801561031f57600080fd5b506101b060b481565b34801561033457600080fd5b506101b060025481565b34801561034a57600080fd5b50610129610359366004611125565b610d82565b34801561036a57600080fd5b506101b066038d7ea4c6800081565b34801561038557600080fd5b506101b06000805160206114f483398151915281565b3480156103a757600080fd5b506103fc6103b636600461110c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044457600080fd5b506101b06104533660046110f1565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b148061049f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f48339815191526104bd81610da7565b6104d56000805160206114f483398151915283610d82565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052a81610da7565b6105348383610db4565b505050565b6001600160a01b03811633146105ae5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105b88282610e38565b5050565b6000805160206114f48339815191526105d481610da7565b6000838152600160205260408120805490910361060457604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106305760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106bc57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610693576040519150601f19603f3d011682016040523d82523d6000602084013e610698565b606091505b50509050806106ba57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106eb908290610100900460ff16611323565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f483398151915261078681610da7565b60028054600091826107978361133c565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090591815260200190565b60405180910390a395945050505050565b814710156109375760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099a576040516360b39bc560e01b815260040160405180910390fd5b60006109a585610b53565b9050838110156109c85760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109da9190611355565b90506000826109e98784611368565b6109f3919061137f565b9050808460010154610a0591906113a1565b846001018190555085846002016000828254610a219190611355565b9091555050604051600090339088908381818185875af1925050503d8060008114610a68576040519150601f19603f3d011682016040523d82523d6000602084013e610a6d565b606091505b5050905080610a8f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad7918b918b918e9160ff8083169261010090041690611404565b60405180910390a25050505050505050565b6000805160206114f4833981519152610b0181610da7565b610b196000805160206114f48339815191528361050f565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bea5750600092915050565b6000816020015142610bfc9190611355565b9050600060b4828460000151610c129190611368565b610c1c919061137f565b905082604001518111610c2f5780610c35565b82604001515b95945050505050565b6000805160206114f4833981519152610c5681610da7565b60008681526001602052604081208054909103610c8657604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d6d57600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610d9d81610da7565b6105348383610e38565b610db18133610e9d565b50565b610dbe8282610d28565b6105b8576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e428282610d28565b156105b8576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610ea78282610d28565b6105b857610eb481610ef6565b610ebf836020610f08565b604051602001610ed092919061143e565b60408051601f198184030181529082905262461bcd60e51b82526105a5916004016114b3565b606061049f6001600160a01b03831660145b60606000610f17836002611368565b610f229060026113a1565b67ffffffffffffffff811115610f3a57610f3a6111c0565b6040519080825280601f01601f191660200182016040528015610f64576020820181803683370190505b509050600360fc1b81600081518110610f7f57610f7f6114c6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fae57610fae6114c6565b60200101906001600160f81b031916908160001a9053506000610fd2846002611368565b610fdd9060016113a1565b90505b6001811115611055576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611011576110116114c6565b1a60f81b828281518110611027576110276114c6565b60200101906001600160f81b031916908160001a90535060049490941c9361104e816114dc565b9050610fe0565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a5565b9392505050565b6000602082840312156110bd57600080fd5b81356001600160e01b0319811681146110a457600080fd5b80356001600160a01b03811681146110ec57600080fd5b919050565b60006020828403121561110357600080fd5b6110a4826110d5565b60006020828403121561111e57600080fd5b5035919050565b6000806040838503121561113857600080fd5b82359150611148602084016110d5565b90509250929050565b6000806040838503121561116457600080fd5b50508035926020909101359150565b803560ff811681146110ec57600080fd5b60008060006060848603121561119957600080fd5b6111a2846110d5565b9250602084013591506111b760408501611173565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111eb57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121157600080fd5b818601915086601f83011261122557600080fd5b813581811115611237576112376111c0565b604051601f8201601f19908116603f0116810190838211818310171561125f5761125f6111c0565b8160405282815289602084870101111561127857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b257600080fd5b853594506020860135935060408601359250606086013591506112d760808701611173565b90509295509295909350565b600080604083850312156112f657600080fd5b6112ff836110d5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111561049f5761049f61130d565b60006001820161134e5761134e61130d565b5060010190565b8181038181111561049f5761049f61130d565b808202811582820484141761049f5761049f61130d565b60008261139c57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561049f5761049f61130d565b60005b838110156113cf5781810151838201526020016113b7565b50506000910152565b600081518084526113f08160208601602086016113b4565b601f01601f19169290920160200192915050565b85815260a06020820152600061141d60a08301876113d8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516114768160178501602088016113b4565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114a78160288401602088016113b4565b01602801949350505050565b6020815260006110a460208301846113d8565b634e487b7160e01b600052603260045260246000fd5b6000816114eb576114eb61130d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220ff6e1722a4db24900b0b16bf92418a2f66f8054b2e46c6f8d1b867836d7aa23b64736f6c63430008110033b19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e", - "deployedBytecode": "0x6080604052600436106101225760003560e01c80638f9eb24d116100a5578063bb8b3ea91161006c578063bb8b3ea914610328578063d547741f1461033e578063dd7dc9a91461035e578063e58378bb14610379578063ed2c9d091461039b578063f1f693d11461043857005b80638f9eb24d1461029e57806391d14854146102be578063a217fddf146102de578063ae69f6db146102f3578063b493eca11461031357005b8063378c3286116100e9578063378c3286146101fe578063543d55d51461021e5780636770c53f1461023e5780637065cb481461025e5780637370c2241461027e57005b806301ffc9a71461012b578063173825d914610160578063248a9ca3146101805780632f2ff15d146101be57806336568abe146101de57005b3661012957005b005b34801561013757600080fd5b5061014b6101463660046110ab565b61046e565b60405190151581526020015b60405180910390f35b34801561016c57600080fd5b5061012961017b3660046110f1565b6104a5565b34801561018c57600080fd5b506101b061019b36600461110c565b60009081526020819052604090206001015490565b604051908152602001610157565b3480156101ca57600080fd5b506101296101d9366004611125565b61050f565b3480156101ea57600080fd5b506101296101f9366004611125565b610539565b34801561020a57600080fd5b50610129610219366004611151565b6105bc565b34801561022a57600080fd5b506101b0610239366004611184565b61076c565b34801561024a57600080fd5b506101296102593660046111d6565b610916565b34801561026a57600080fd5b506101296102793660046110f1565b610ae9565b34801561028a57600080fd5b506101b061029936600461110c565b610b53565b3480156102aa57600080fd5b506101296102b936600461129a565b610c3e565b3480156102ca57600080fd5b5061014b6102d9366004611125565b610d28565b3480156102ea57600080fd5b506101b0600081565b3480156102ff57600080fd5b506101b061030e3660046112e3565b610d51565b34801561031f57600080fd5b506101b060b481565b34801561033457600080fd5b506101b060025481565b34801561034a57600080fd5b50610129610359366004611125565b610d82565b34801561036a57600080fd5b506101b066038d7ea4c6800081565b34801561038557600080fd5b506101b06000805160206114f483398151915281565b3480156103a757600080fd5b506103fc6103b636600461110c565b6001602081905260009182526040909120805491810154600282015460039092015490919060ff808216916101008104909116906201000090046001600160a01b031686565b6040805196875260208701959095529385019290925260ff90811660608501521660808301526001600160a01b031660a082015260c001610157565b34801561044457600080fd5b506101b06104533660046110f1565b6001600160a01b031660009081526003602052604090205490565b60006001600160e01b03198216637965db0b60e01b148061049f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206114f48339815191526104bd81610da7565b6104d56000805160206114f483398151915283610d82565b60405133906001600160a01b038416907fca273b61904dd225d0c1e905343c24040cecad0b4491337492c990845edb525790600090a35050565b60008281526020819052604090206001015461052a81610da7565b6105348383610db4565b505050565b6001600160a01b03811633146105ae5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105b88282610e38565b5050565b6000805160206114f48339815191526105d481610da7565b6000838152600160205260408120805490910361060457604051631b017f1760e11b815260040160405180910390fd5b66038d7ea4c68000816002015411156106305760405163d4eff9fb60e01b815260040160405180910390fd5b6002810154156106bc57600381015460028201546040516000926201000090046001600160a01b031691908381818185875af1925050503d8060008114610693576040519150601f19603f3d011682016040523d82523d6000602084013e610698565b606091505b50509050806106ba57604051630dcf35db60e41b815260040160405180910390fd5b505b828155426001808301919091556002820184905560038201805482906106eb908290610100900460ff16611323565b825461010092830a60ff8181021990921692821602919091179092556003840154604080518881528285166020820152928204909316828401529151620100009092046001600160a01b0316925086917f17ee42885f0e22165eac00b186d2f6967173c5d903e21a7d80ceddf6645e2e8c916060908290030190a350505050565b60006000805160206114f483398151915261078681610da7565b60028054600091826107978361133c565b9190505590506040518060c001604052808681526020014281526020018681526020018560ff168152602001600160ff168152602001876001600160a01b03168152506001600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff021916908360ff16021790555060808201518160030160016101000a81548160ff021916908360ff16021790555060a08201518160030160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505060036000876001600160a01b03166001600160a01b03168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055856001600160a01b0316817f4d140f3ab7e8fb4ad26897fc618b16b04dc99070c528dc3f0a83a4ee095bb38c8760405161090591815260200190565b60405180910390a395945050505050565b814710156109375760405163a3fb8f9d60e01b815260040160405180910390fd5b6000838152600160205260408120805490910361096757604051631b017f1760e11b815260040160405180910390fd5b60038101546201000090046001600160a01b0316331461099a576040516360b39bc560e01b815260040160405180910390fd5b60006109a585610b53565b9050838110156109c85760405163347efb5160e01b815260040160405180910390fd5b60008260010154426109da9190611355565b90506000826109e98784611368565b6109f3919061137f565b9050808460010154610a0591906113a1565b846001018190555085846002016000828254610a219190611355565b9091555050604051600090339088908381818185875af1925050503d8060008114610a68576040519150601f19603f3d011682016040523d82523d6000602084013e610a6d565b606091505b5050905080610a8f57604051630dcf35db60e41b815260040160405180910390fd5b600385015460405133917f47c0670222fad9b95e64bb97dfc188690542d35c688bd1621c1d82b0420e0f0d91610ad7918b918b918e9160ff8083169261010090041690611404565b60405180910390a25050505050505050565b6000805160206114f4833981519152610b0181610da7565b610b196000805160206114f48339815191528361050f565b60405133906001600160a01b038416907f91a3131740191cd3eb4fc72bf2cbcd5ab483dcdf168f2307451becc3e5dae55690600090a35050565b6000818152600160208181526040808420815160c081018352815480825294820154938101939093526002810154918301919091526003015460ff808216606084015261010082041660808301526201000090046001600160a01b031660a0820152908203610bd557604051631b017f1760e11b815260040160405180910390fd5b8060400151600003610bea5750600092915050565b6000816020015142610bfc9190611355565b9050600060b4828460000151610c129190611368565b610c1c919061137f565b905082604001518111610c2f5780610c35565b82604001515b95945050505050565b6000805160206114f4833981519152610c5681610da7565b60008681526001602052604081208054909103610c8657604051631b017f1760e11b815260040160405180910390fd5b858155600181018590556002810184905560038101805461ff0019811661010060ff878116820292831794859055604080518c8152602081018c90529081018a90529381169281169290921760608401528304166080820152620100009091046001600160a01b03169088907f548e40d7e4654aa5af9a6984f2cea5a5b9bbd2104ecdfeea5858590c6672694c9060a00160405180910390a350505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60036020528160005260406000208181548110610d6d57600080fd5b90600052602060002001600091509150505481565b600082815260208190526040902060010154610d9d81610da7565b6105348383610e38565b610db18133610e9d565b50565b610dbe8282610d28565b6105b8576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610df43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610e428282610d28565b156105b8576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610ea78282610d28565b6105b857610eb481610ef6565b610ebf836020610f08565b604051602001610ed092919061143e565b60408051601f198184030181529082905262461bcd60e51b82526105a5916004016114b3565b606061049f6001600160a01b03831660145b60606000610f17836002611368565b610f229060026113a1565b67ffffffffffffffff811115610f3a57610f3a6111c0565b6040519080825280601f01601f191660200182016040528015610f64576020820181803683370190505b509050600360fc1b81600081518110610f7f57610f7f6114c6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610fae57610fae6114c6565b60200101906001600160f81b031916908160001a9053506000610fd2846002611368565b610fdd9060016113a1565b90505b6001811115611055576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611011576110116114c6565b1a60f81b828281518110611027576110276114c6565b60200101906001600160f81b031916908160001a90535060049490941c9361104e816114dc565b9050610fe0565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105a5565b9392505050565b6000602082840312156110bd57600080fd5b81356001600160e01b0319811681146110a457600080fd5b80356001600160a01b03811681146110ec57600080fd5b919050565b60006020828403121561110357600080fd5b6110a4826110d5565b60006020828403121561111e57600080fd5b5035919050565b6000806040838503121561113857600080fd5b82359150611148602084016110d5565b90509250929050565b6000806040838503121561116457600080fd5b50508035926020909101359150565b803560ff811681146110ec57600080fd5b60008060006060848603121561119957600080fd5b6111a2846110d5565b9250602084013591506111b760408501611173565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111eb57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561121157600080fd5b818601915086601f83011261122557600080fd5b813581811115611237576112376111c0565b604051601f8201601f19908116603f0116810190838211818310171561125f5761125f6111c0565b8160405282815289602084870101111561127857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600080600080600060a086880312156112b257600080fd5b853594506020860135935060408601359250606086013591506112d760808701611173565b90509295509295909350565b600080604083850312156112f657600080fd5b6112ff836110d5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111561049f5761049f61130d565b60006001820161134e5761134e61130d565b5060010190565b8181038181111561049f5761049f61130d565b808202811582820484141761049f5761049f61130d565b60008261139c57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561049f5761049f61130d565b60005b838110156113cf5781810151838201526020016113b7565b50506000910152565b600081518084526113f08160208601602086016113b4565b601f01601f19169290920160200192915050565b85815260a06020820152600061141d60a08301876113d8565b60408301959095525060ff9283166060820152911660809091015292915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516114768160178501602088016113b4565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516114a78160288401602088016113b4565b01602801949350505050565b6020815260006110a460208301846113d8565b634e487b7160e01b600052603260045260246000fd5b6000816114eb576114eb61130d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214ea2646970667358221220ff6e1722a4db24900b0b16bf92418a2f66f8054b2e46c6f8d1b867836d7aa23b64736f6c63430008110033", - "devdoc": { - "kind": "dev", - "methods": { - "getRoleAdmin(bytes32)": { - "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." - }, - "grantRole(bytes32,address)": { - "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event." - }, - "hasRole(bytes32,address)": { - "details": "Returns `true` if `account` has been granted `role`." - }, - "renounceRole(bytes32,address)": { - "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`. May emit a {RoleRevoked} event." - }, - "revokeRole(bytes32,address)": { - "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event." - }, - "supportsInterface(bytes4)": { - "details": "See {IERC165-supportsInterface}." - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - }, - "storageLayout": { - "storage": [ - { - "astId": 24, - "contract": "contracts/Stream.sol:Stream", - "label": "_roles", - "offset": 0, - "slot": "0", - "type": "t_mapping(t_bytes32,t_struct(RoleData)19_storage)" - }, - { - "astId": 1514, - "contract": "contracts/Stream.sol:Stream", - "label": "grantStreams", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_uint256,t_struct(GrantStream)1509_storage)" - }, - { - "astId": 1517, - "contract": "contracts/Stream.sol:Stream", - "label": "nextGrantId", - "offset": 0, - "slot": "2", - "type": "t_uint256" - }, - { - "astId": 1522, - "contract": "contracts/Stream.sol:Stream", - "label": "builderGrants", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_array(t_uint256)dyn_storage)" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)dyn_storage": { - "base": "t_uint256", - "encoding": "dynamic_array", - "label": "uint256[]", - "numberOfBytes": "32" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_array(t_uint256)dyn_storage)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => uint256[])", - "numberOfBytes": "32", - "value": "t_array(t_uint256)dyn_storage" - }, - "t_mapping(t_address,t_bool)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => bool)", - "numberOfBytes": "32", - "value": "t_bool" - }, - "t_mapping(t_bytes32,t_struct(RoleData)19_storage)": { - "encoding": "mapping", - "key": "t_bytes32", - "label": "mapping(bytes32 => struct AccessControl.RoleData)", - "numberOfBytes": "32", - "value": "t_struct(RoleData)19_storage" - }, - "t_mapping(t_uint256,t_struct(GrantStream)1509_storage)": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => struct Stream.GrantStream)", - "numberOfBytes": "32", - "value": "t_struct(GrantStream)1509_storage" - }, - "t_struct(GrantStream)1509_storage": { - "encoding": "inplace", - "label": "struct Stream.GrantStream", - "members": [ - { - "astId": 1498, - "contract": "contracts/Stream.sol:Stream", - "label": "cap", - "offset": 0, - "slot": "0", - "type": "t_uint256" - }, - { - "astId": 1500, - "contract": "contracts/Stream.sol:Stream", - "label": "last", - "offset": 0, - "slot": "1", - "type": "t_uint256" - }, - { - "astId": 1502, - "contract": "contracts/Stream.sol:Stream", - "label": "amountLeft", - "offset": 0, - "slot": "2", - "type": "t_uint256" - }, - { - "astId": 1504, - "contract": "contracts/Stream.sol:Stream", - "label": "grantNumber", - "offset": 0, - "slot": "3", - "type": "t_uint8" - }, - { - "astId": 1506, - "contract": "contracts/Stream.sol:Stream", - "label": "stageNumber", - "offset": 1, - "slot": "3", - "type": "t_uint8" - }, - { - "astId": 1508, - "contract": "contracts/Stream.sol:Stream", - "label": "builder", - "offset": 2, - "slot": "3", - "type": "t_address" - } - ], - "numberOfBytes": "128" - }, - "t_struct(RoleData)19_storage": { - "encoding": "inplace", - "label": "struct AccessControl.RoleData", - "members": [ - { - "astId": 16, - "contract": "contracts/Stream.sol:Stream", - "label": "members", - "offset": 0, - "slot": "0", - "type": "t_mapping(t_address,t_bool)" - }, - { - "astId": 18, - "contract": "contracts/Stream.sol:Stream", - "label": "adminRole", - "offset": 0, - "slot": "1", - "type": "t_bytes32" - } - ], - "numberOfBytes": "64" - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "encoding": "inplace", - "label": "uint8", - "numberOfBytes": "1" - } - } - } -} \ No newline at end of file diff --git a/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json b/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json deleted file mode 100644 index fadf364..0000000 --- a/packages/hardhat/deployments/sepolia/solcInputs/66949c7747c59450b1528b6c03e97e3b.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "language": "Solidity", - "sources": { - "@openzeppelin/contracts/access/AccessControl.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" - }, - "@openzeppelin/contracts/access/IAccessControl.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" - }, - "@openzeppelin/contracts/utils/Context.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" - }, - "@openzeppelin/contracts/utils/introspection/ERC165.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" - }, - "@openzeppelin/contracts/utils/introspection/IERC165.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" - }, - "@openzeppelin/contracts/utils/math/Math.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" - }, - "@openzeppelin/contracts/utils/Strings.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" - }, - "contracts/Stream.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ncontract Stream is AccessControl {\n\tbytes32 public constant OWNER_ROLE = keccak256(\"OWNER_ROLE\");\n\n\tstruct GrantStream {\n\t\tuint256 cap;\n\t\tuint256 last;\n\t\tuint256 amountLeft;\n\t\tuint8 grantNumber;\n\t\tuint8 stageNumber;\n\t\taddress builder;\n\t}\n\n\tmapping(uint256 => GrantStream) public grantStreams;\n\tuint256 public nextGrantId = 1;\n\n\tmapping(address => uint256[]) public builderGrants;\n\n\tuint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 30 days\n\tuint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH\n\n\tevent Withdraw(\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tstring reason,\n\t\tuint256 grantId,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);\n\tevent MoveGrantToNextStage(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 amount,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent UpdateGrant(\n\t\tuint256 indexed grantId,\n\t\taddress indexed to,\n\t\tuint256 cap,\n\t\tuint256 last,\n\t\tuint256 amountLeft,\n\t\tuint8 grantNumber,\n\t\tuint8 stageNumber\n\t);\n\tevent AddOwner(address indexed newOwner, address indexed addedBy);\n\tevent RemoveOwner(address indexed removedOwner, address indexed removedBy);\n\n\t// Custom errors\n\terror NoActiveStream();\n\terror InsufficientContractFunds();\n\terror UnauthorizedWithdrawal();\n\terror InsufficientStreamFunds();\n\terror FailedToSendEther();\n\terror PreviousAmountNotFullyWithdrawn();\n\n\tconstructor(address[] memory _initialOwners) {\n\t\t_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);\n\t\tfor (uint i = 0; i < _initialOwners.length; i++) {\n\t\t\t_grantRole(OWNER_ROLE, _initialOwners[i]);\n\t\t}\n\t}\n\n\tfunction unlockedGrantAmount(\n\t\tuint256 _grantId\n\t) public view returns (uint256) {\n\t\tGrantStream memory grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft == 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 unlockedAmount = (grantStream.cap * elapsedTime) /\n\t\t\tFULL_STREAM_UNLOCK_PERIOD;\n\n\t\treturn\n\t\t\tunlockedAmount > grantStream.amountLeft\n\t\t\t\t? grantStream.amountLeft\n\t\t\t\t: unlockedAmount;\n\t}\n\n\tfunction addGrantStream(\n\t\taddress _builder,\n\t\tuint256 _cap,\n\t\tuint8 _grantNumber\n\t) public onlyRole(OWNER_ROLE) returns (uint256) {\n\t\tuint256 grantId = nextGrantId++;\n\t\tgrantStreams[grantId] = GrantStream({\n\t\t\tcap: _cap,\n\t\t\tlast: block.timestamp,\n\t\t\tamountLeft: _cap,\n\t\t\tgrantNumber: _grantNumber,\n\t\t\tstageNumber: 1,\n\t\t\tbuilder: _builder\n\t\t});\n\t\tbuilderGrants[_builder].push(grantId);\n\t\temit AddGrant(grantId, _builder, _cap);\n\t\treturn grantId;\n\t}\n\n\tfunction moveGrantToNextStage(\n\t\tuint256 _grantId,\n\t\tuint256 _cap\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\n\t\tif (grantStream.amountLeft > DUST_THRESHOLD)\n\t\t\trevert PreviousAmountNotFullyWithdrawn();\n\n\t\tif (grantStream.amountLeft > 0) {\n\t\t\t(bool sent, ) = payable(grantStream.builder).call{\n\t\t\t\tvalue: grantStream.amountLeft\n\t\t\t}(\"\");\n\t\t\tif (!sent) revert FailedToSendEther();\n\t\t}\n\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = block.timestamp;\n\t\tgrantStream.amountLeft = _cap;\n\t\tgrantStream.stageNumber += 1;\n\n\t\temit MoveGrantToNextStage(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction updateGrant(\n\t\tuint256 _grantId,\n\t\tuint256 _cap,\n\t\tuint256 _last,\n\t\tuint256 _amountLeft,\n\t\tuint8 _stageNumber\n\t) public onlyRole(OWNER_ROLE) {\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tgrantStream.cap = _cap;\n\t\tgrantStream.last = _last;\n\t\tgrantStream.amountLeft = _amountLeft;\n\t\tgrantStream.stageNumber = _stageNumber;\n\n\t\temit UpdateGrant(\n\t\t\t_grantId,\n\t\t\tgrantStream.builder,\n\t\t\t_cap,\n\t\t\tgrantStream.last,\n\t\t\tgrantStream.amountLeft,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction streamWithdraw(\n\t\tuint256 _grantId,\n\t\tuint256 _amount,\n\t\tstring memory _reason\n\t) public {\n\t\tif (address(this).balance < _amount) revert InsufficientContractFunds();\n\t\tGrantStream storage grantStream = grantStreams[_grantId];\n\t\tif (grantStream.cap == 0) revert NoActiveStream();\n\t\tif (msg.sender != grantStream.builder) revert UnauthorizedWithdrawal();\n\n\t\tuint256 totalAmountCanWithdraw = unlockedGrantAmount(_grantId);\n\t\tif (totalAmountCanWithdraw < _amount) revert InsufficientStreamFunds();\n\n\t\tuint256 elapsedTime = block.timestamp - grantStream.last;\n\t\tuint256 timeToDeduct = (elapsedTime * _amount) / totalAmountCanWithdraw;\n\n\t\tgrantStream.last = grantStream.last + timeToDeduct;\n\t\tgrantStream.amountLeft -= _amount;\n\n\t\t(bool sent, ) = msg.sender.call{ value: _amount }(\"\");\n\t\tif (!sent) revert FailedToSendEther();\n\n\t\temit Withdraw(\n\t\t\tmsg.sender,\n\t\t\t_amount,\n\t\t\t_reason,\n\t\t\t_grantId,\n\t\t\tgrantStream.grantNumber,\n\t\t\tgrantStream.stageNumber\n\t\t);\n\t}\n\n\tfunction getBuilderGrantCount(\n\t\taddress _builder\n\t) public view returns (uint256) {\n\t\treturn builderGrants[_builder].length;\n\t}\n\n\tfunction addOwner(address newOwner) public onlyRole(OWNER_ROLE) {\n\t\tgrantRole(OWNER_ROLE, newOwner);\n\t\temit AddOwner(newOwner, msg.sender);\n\t}\n\n\tfunction removeOwner(address owner) public onlyRole(OWNER_ROLE) {\n\t\trevokeRole(OWNER_ROLE, owner);\n\t\temit RemoveOwner(owner, msg.sender);\n\t}\n\n\treceive() external payable {}\n\n\tfallback() external payable {}\n}\n" - } - }, - "settings": { - "optimizer": { - "enabled": true, - "runs": 200 - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata", - "devdoc", - "userdoc", - "storageLayout", - "evm.gasEstimates" - ], - "": [ - "ast" - ] - } - }, - "metadata": { - "useLiteralContent": true - } - } -} \ No newline at end of file diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 268bc2d..a5ce03b 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -849,1598 +849,6 @@ const deployedContracts = { }, }, }, - 31337: { - Stream: { - address: "0x5FbDB2315678afecb367f032d93F642f64180aa3", - abi: [ - { - inputs: [ - { - internalType: "address[]", - name: "_initialOwners", - type: "address[]", - }, - ], - stateMutability: "nonpayable", - type: "constructor", - }, - { - inputs: [], - name: "AlreadyWithdrawnFromGrant", - type: "error", - }, - { - inputs: [], - name: "FailedToSendEther", - type: "error", - }, - { - inputs: [], - name: "InsufficientContractFunds", - type: "error", - }, - { - inputs: [], - name: "InsufficientStreamFunds", - type: "error", - }, - { - inputs: [], - name: "NoActiveStream", - type: "error", - }, - { - inputs: [], - name: "PreviousAmountNotFullyWithdrawn", - type: "error", - }, - { - inputs: [], - name: "UnauthorizedWithdrawal", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - ], - name: "AddGrant", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "newOwner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "addedBy", - type: "address", - }, - ], - name: "AddOwner", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "MoveGrantToNextStage", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - ], - name: "ReinitializeGrant", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "builder", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "ReinitializeNextStage", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "removedOwner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "removedBy", - type: "address", - }, - ], - name: "RemoveOwner", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "previousAdminRole", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "newAdminRole", - type: "bytes32", - }, - ], - name: "RoleAdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "RoleGranted", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "RoleRevoked", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "cap", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "last", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "amountLeft", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "UpdateGrant", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "string", - name: "reason", - type: "string", - }, - { - indexed: false, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "Withdraw", - type: "event", - }, - { - stateMutability: "payable", - type: "fallback", - }, - { - inputs: [], - name: "DEFAULT_ADMIN_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "DUST_THRESHOLD", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "FULL_STREAM_UNLOCK_PERIOD", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "OWNER_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_builder", - type: "address", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - { - internalType: "uint8", - name: "_grantNumber", - type: "uint8", - }, - ], - name: "addGrantStream", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newOwner", - type: "address", - }, - ], - name: "addOwner", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - name: "builderGrants", - outputs: [ - { - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_builder", - type: "address", - }, - ], - name: "getBuilderGrantCount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_builder", - type: "address", - }, - { - internalType: "uint8", - name: "_grantNumber", - type: "uint8", - }, - ], - name: "getGrantIdByBuilderAndGrantNumber", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - ], - name: "getRoleAdmin", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "grantRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - name: "grantStreams", - outputs: [ - { - internalType: "uint256", - name: "cap", - type: "uint256", - }, - { - internalType: "uint256", - name: "last", - type: "uint256", - }, - { - internalType: "uint256", - name: "amountLeft", - type: "uint256", - }, - { - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - { - internalType: "address", - name: "builder", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "hasRole", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - ], - name: "moveGrantToNextStage", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "nextGrantId", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - ], - name: "removeOwner", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "renounceRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "revokeRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_amount", - type: "uint256", - }, - { - internalType: "string", - name: "_reason", - type: "string", - }, - ], - name: "streamWithdraw", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes4", - name: "interfaceId", - type: "bytes4", - }, - ], - name: "supportsInterface", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - ], - name: "unlockedGrantAmount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - { - internalType: "uint256", - name: "_last", - type: "uint256", - }, - { - internalType: "uint256", - name: "_amountLeft", - type: "uint256", - }, - { - internalType: "uint8", - name: "_stageNumber", - type: "uint8", - }, - ], - name: "updateGrant", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - stateMutability: "payable", - type: "receive", - }, - ], - inheritedFunctions: { - DEFAULT_ADMIN_ROLE: "@openzeppelin/contracts/access/AccessControl.sol", - getRoleAdmin: "@openzeppelin/contracts/access/AccessControl.sol", - grantRole: "@openzeppelin/contracts/access/AccessControl.sol", - hasRole: "@openzeppelin/contracts/access/AccessControl.sol", - renounceRole: "@openzeppelin/contracts/access/AccessControl.sol", - revokeRole: "@openzeppelin/contracts/access/AccessControl.sol", - supportsInterface: "@openzeppelin/contracts/access/AccessControl.sol", - }, - }, - }, - 11155111: { - Stream: { - address: "0x725d9b8265CF7Cb77478C83fCC82020f789a389f", - abi: [ - { - inputs: [ - { - internalType: "address[]", - name: "_initialOwners", - type: "address[]", - }, - ], - stateMutability: "nonpayable", - type: "constructor", - }, - { - inputs: [], - name: "FailedToSendEther", - type: "error", - }, - { - inputs: [], - name: "InsufficientContractFunds", - type: "error", - }, - { - inputs: [], - name: "InsufficientStreamFunds", - type: "error", - }, - { - inputs: [], - name: "NoActiveStream", - type: "error", - }, - { - inputs: [], - name: "PreviousAmountNotFullyWithdrawn", - type: "error", - }, - { - inputs: [], - name: "UnauthorizedWithdrawal", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - ], - name: "AddGrant", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "newOwner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "addedBy", - type: "address", - }, - ], - name: "AddOwner", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "MoveGrantToNextStage", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "removedOwner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "removedBy", - type: "address", - }, - ], - name: "RemoveOwner", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "previousAdminRole", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "newAdminRole", - type: "bytes32", - }, - ], - name: "RoleAdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "RoleGranted", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "RoleRevoked", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "cap", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "last", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "amountLeft", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "UpdateGrant", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "string", - name: "reason", - type: "string", - }, - { - indexed: false, - internalType: "uint256", - name: "grantId", - type: "uint256", - }, - { - indexed: false, - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - indexed: false, - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - ], - name: "Withdraw", - type: "event", - }, - { - stateMutability: "payable", - type: "fallback", - }, - { - inputs: [], - name: "DEFAULT_ADMIN_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "DUST_THRESHOLD", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "FULL_STREAM_UNLOCK_PERIOD", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "OWNER_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_builder", - type: "address", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - { - internalType: "uint8", - name: "_grantNumber", - type: "uint8", - }, - ], - name: "addGrantStream", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newOwner", - type: "address", - }, - ], - name: "addOwner", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - name: "builderGrants", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_builder", - type: "address", - }, - ], - name: "getBuilderGrantCount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - ], - name: "getRoleAdmin", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "grantRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - name: "grantStreams", - outputs: [ - { - internalType: "uint256", - name: "cap", - type: "uint256", - }, - { - internalType: "uint256", - name: "last", - type: "uint256", - }, - { - internalType: "uint256", - name: "amountLeft", - type: "uint256", - }, - { - internalType: "uint8", - name: "grantNumber", - type: "uint8", - }, - { - internalType: "uint8", - name: "stageNumber", - type: "uint8", - }, - { - internalType: "address", - name: "builder", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "hasRole", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - ], - name: "moveGrantToNextStage", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "nextGrantId", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - ], - name: "removeOwner", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "renounceRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "revokeRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_amount", - type: "uint256", - }, - { - internalType: "string", - name: "_reason", - type: "string", - }, - ], - name: "streamWithdraw", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes4", - name: "interfaceId", - type: "bytes4", - }, - ], - name: "supportsInterface", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - ], - name: "unlockedGrantAmount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_grantId", - type: "uint256", - }, - { - internalType: "uint256", - name: "_cap", - type: "uint256", - }, - { - internalType: "uint256", - name: "_last", - type: "uint256", - }, - { - internalType: "uint256", - name: "_amountLeft", - type: "uint256", - }, - { - internalType: "uint8", - name: "_stageNumber", - type: "uint8", - }, - ], - name: "updateGrant", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - stateMutability: "payable", - type: "receive", - }, - ], - inheritedFunctions: { - DEFAULT_ADMIN_ROLE: "@openzeppelin/contracts/access/AccessControl.sol", - getRoleAdmin: "@openzeppelin/contracts/access/AccessControl.sol", - grantRole: "@openzeppelin/contracts/access/AccessControl.sol", - hasRole: "@openzeppelin/contracts/access/AccessControl.sol", - renounceRole: "@openzeppelin/contracts/access/AccessControl.sol", - revokeRole: "@openzeppelin/contracts/access/AccessControl.sol", - supportsInterface: "@openzeppelin/contracts/access/AccessControl.sol", - }, - }, - }, } as const; export default deployedContracts satisfies GenericContractsDeclaration;