├── .changeset ├── config.json └── smooth-balloons-stare.md ├── .devcontainer ├── Dockerfile ├── README.md ├── devcontainer.json ├── docker-compose.yml ├── host-setup.sh ├── project-setup.sh ├── sample-graph.env └── setup-git-signing.sh ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ ├── build.yml │ ├── ci-contracts.yml │ ├── ci-data-edge.yml │ ├── ci-token-dist.yml │ ├── lint.yml │ ├── publish.yml │ └── verifydeployed.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .markdownlint.json ├── .solhint.json ├── .yamllint ├── .yarn └── patches │ └── typechain-npm-8.3.2-b02e27439e.patch ├── .yarnrc.yml ├── LICENSE ├── README.md ├── commitlint.config.js ├── eslint.config.mjs ├── package.json ├── packages ├── contracts │ ├── .env.example │ ├── .markdownlint.json │ ├── .mocharc.json │ ├── .solcover.js │ ├── CHANGELOG.md │ ├── DEPLOYMENT.md │ ├── README.md │ ├── TESTING.md │ ├── addresses-staging.json │ ├── addresses.json │ ├── arbitrum-addresses.json │ ├── audits │ │ ├── ConsenSysDiligence │ │ │ ├── 2021-05-graph-initial-review.pdf │ │ │ ├── 2021-08-staking-multicall-and-delegation-fixes.pdf │ │ │ ├── 2022-01-graph-pr527-audit.pdf │ │ │ └── 2022-03-graph-altruistic-alloc-and-query-versioning.pdf │ │ ├── OpenZeppelin │ │ │ ├── 2020-08-graph-protocol.pdf │ │ │ ├── 2021-04-graph-addresses-cache-audit.pdf │ │ │ ├── 2021-04-graph-governance-upgrade-audit.pdf │ │ │ ├── 2021-04-graph-rewardsmanager-upgrade-audit.pdf │ │ │ ├── 2021-04-graph-slashing-upgrade-audit.pdf │ │ │ ├── 2021-04-graph-staking-bugfix-2-audit.pdf │ │ │ ├── 2021-04-graph-staking-bugfix-audit-1.pdf │ │ │ ├── 2021-08-graph-gns-audit.pdf │ │ │ ├── 2021-11-graph-curation-minimal-proxy.pdf │ │ │ ├── 2021-11-graph-gns-transferrable-owner.pdf │ │ │ ├── 2021-12-graph-rewards-signal-threshold.pdf │ │ │ ├── 2022-07-graph-arbitrum-bridge-audit.pdf │ │ │ ├── 2022-07-pr552-summary.pdf │ │ │ ├── 2022-07-pr568-summary.pdf │ │ │ ├── 2022-07-pr569-summary.pdf │ │ │ ├── 2022-07-pr571-summary.pdf │ │ │ ├── 2022-09-graph-drip-keeper-reward-audit.pdf │ │ │ ├── 2023-05-staking-vesting-l2.pdf │ │ │ ├── 2023-06-graph-exponential-rebates.pdf │ │ │ ├── 2023-08-dispute-manager-status.pdf │ │ │ ├── 2023-11-permissionless-payers.pdf │ │ │ ├── 2023-11-remove-delegation-parameters-cooldown.pdf │ │ │ ├── 2024-02-graph-availability-manager-minimum-allocation-removal.pdf │ │ │ └── 2024-02-subgraph-availability-manager-and-minimum-allocation-duration-removal.pdf │ │ └── Trust │ │ │ └── 2023-02-operator-decentralization-pr749.pdf │ ├── config │ │ ├── graph.arbitrum-goerli.yml │ │ ├── graph.arbitrum-hardhat.yml │ │ ├── graph.arbitrum-localhost.yml │ │ ├── graph.arbitrum-one.yml │ │ ├── graph.arbitrum-sepolia.yml │ │ ├── graph.goerli.yml │ │ ├── graph.hardhat.yml │ │ ├── graph.localhost.yml │ │ ├── graph.mainnet.yml │ │ └── graph.sepolia.yml │ ├── contracts │ │ ├── .gitattributes │ │ ├── arbitrum │ │ │ ├── AddressAliasHelper.sol │ │ │ ├── IArbToken.sol │ │ │ ├── IBridge.sol │ │ │ ├── IInbox.sol │ │ │ ├── IMessageProvider.sol │ │ │ ├── IOutbox.sol │ │ │ ├── ITokenGateway.sol │ │ │ ├── L1ArbitrumMessenger.sol │ │ │ ├── L2ArbitrumMessenger.sol │ │ │ └── README.md │ │ ├── bancor │ │ │ └── BancorFormula.sol │ │ ├── base │ │ │ ├── IMulticall.sol │ │ │ └── Multicall.sol │ │ ├── curation │ │ │ ├── Curation.sol │ │ │ ├── CurationStorage.sol │ │ │ ├── GraphCurationToken.sol │ │ │ ├── ICuration.sol │ │ │ └── IGraphCurationToken.sol │ │ ├── discovery │ │ │ ├── GNS.sol │ │ │ ├── GNSStorage.sol │ │ │ ├── IGNS.sol │ │ │ ├── IServiceRegistry.sol │ │ │ ├── ISubgraphNFT.sol │ │ │ ├── ISubgraphNFTDescriptor.sol │ │ │ ├── L1GNS.sol │ │ │ ├── L1GNSStorage.sol │ │ │ ├── ServiceRegistry.sol │ │ │ ├── ServiceRegistryStorage.sol │ │ │ ├── SubgraphNFT.sol │ │ │ ├── SubgraphNFTDescriptor.sol │ │ │ └── erc1056 │ │ │ │ ├── EthereumDIDRegistry.sol │ │ │ │ └── IEthereumDIDRegistry.sol │ │ ├── disputes │ │ │ ├── DisputeManager.sol │ │ │ ├── DisputeManagerStorage.sol │ │ │ └── IDisputeManager.sol │ │ ├── epochs │ │ │ ├── EpochManager.sol │ │ │ ├── EpochManagerStorage.sol │ │ │ └── IEpochManager.sol │ │ ├── gateway │ │ │ ├── BridgeEscrow.sol │ │ │ ├── GraphTokenGateway.sol │ │ │ ├── ICallhookReceiver.sol │ │ │ └── L1GraphTokenGateway.sol │ │ ├── governance │ │ │ ├── Controller.sol │ │ │ ├── Governed.sol │ │ │ ├── IController.sol │ │ │ ├── IManaged.sol │ │ │ ├── Managed.sol │ │ │ └── Pausable.sol │ │ ├── l2 │ │ │ ├── curation │ │ │ │ ├── IL2Curation.sol │ │ │ │ └── L2Curation.sol │ │ │ ├── discovery │ │ │ │ ├── IL2GNS.sol │ │ │ │ ├── L2GNS.sol │ │ │ │ └── L2GNSStorage.sol │ │ │ ├── gateway │ │ │ │ └── L2GraphTokenGateway.sol │ │ │ ├── staking │ │ │ │ ├── IL2Staking.sol │ │ │ │ ├── IL2StakingBase.sol │ │ │ │ └── L2Staking.sol │ │ │ └── token │ │ │ │ ├── GraphTokenUpgradeable.sol │ │ │ │ └── L2GraphToken.sol │ │ ├── libraries │ │ │ ├── Base58Encoder.sol │ │ │ └── HexStrings.sol │ │ ├── payments │ │ │ └── AllocationExchange.sol │ │ ├── rewards │ │ │ ├── IRewardsManager.sol │ │ │ ├── RewardsManager.sol │ │ │ ├── RewardsManagerStorage.sol │ │ │ └── SubgraphAvailabilityManager.sol │ │ ├── staking │ │ │ ├── IL1GraphTokenLockTransferTool.sol │ │ │ ├── IL1Staking.sol │ │ │ ├── IL1StakingBase.sol │ │ │ ├── IStaking.sol │ │ │ ├── IStakingBase.sol │ │ │ ├── IStakingData.sol │ │ │ ├── IStakingExtension.sol │ │ │ ├── L1Staking.sol │ │ │ ├── L1StakingStorage.sol │ │ │ ├── Staking.sol │ │ │ ├── StakingExtension.sol │ │ │ ├── StakingStorage.sol │ │ │ └── libs │ │ │ │ ├── Exponential.sol │ │ │ │ ├── LibFixedMath.sol │ │ │ │ ├── MathUtils.sol │ │ │ │ └── Stakes.sol │ │ ├── tests │ │ │ ├── CallhookReceiverMock.sol │ │ │ ├── GovernedMock.sol │ │ │ ├── L1GraphTokenLockTransferToolBadMock.sol │ │ │ ├── L1GraphTokenLockTransferToolMock.sol │ │ │ ├── LegacyGNSMock.sol │ │ │ ├── arbitrum │ │ │ │ ├── ArbSysMock.sol │ │ │ │ ├── BridgeMock.sol │ │ │ │ ├── InboxMock.sol │ │ │ │ └── OutboxMock.sol │ │ │ └── ens │ │ │ │ ├── IENS.sol │ │ │ │ ├── IPublicResolver.sol │ │ │ │ └── ITestRegistrar.sol │ │ ├── token │ │ │ ├── GraphToken.sol │ │ │ └── IGraphToken.sol │ │ ├── upgrades │ │ │ ├── GraphProxy.sol │ │ │ ├── GraphProxyAdmin.sol │ │ │ ├── GraphProxyStorage.sol │ │ │ ├── GraphUpgradeable.sol │ │ │ └── IGraphProxy.sol │ │ └── utils │ │ │ └── TokenUtils.sol │ ├── hardhat.config.ts │ ├── index.d.ts │ ├── package.json │ ├── prettier.config.cjs │ ├── scripts │ │ ├── analyze │ │ ├── build │ │ ├── clean │ │ ├── coverage │ │ ├── e2e │ │ ├── evm │ │ ├── flatten │ │ ├── myth │ │ ├── ops │ │ │ ├── 20240208-migrate-legacy-subgraphs │ │ │ │ ├── data.json │ │ │ │ └── migrate.ts │ │ │ ├── parseTestnetAddresses.ts │ │ │ └── testDisputeConflict │ │ │ │ ├── acceptDispute.ts │ │ │ │ ├── createDispute.ts │ │ │ │ └── setupIndexer.ts │ │ ├── predeploy │ │ ├── prepack │ │ ├── test │ │ ├── test-coverage-file │ │ └── upgrade │ ├── slither.config.json │ ├── tasks │ │ ├── bridge │ │ │ ├── deposits.ts │ │ │ ├── to-l2.ts │ │ │ └── withdrawals.ts │ │ ├── contract │ │ │ ├── deploy.ts │ │ │ └── upgrade.ts │ │ ├── deployment │ │ │ └── config.ts │ │ ├── e2e │ │ │ └── e2e.ts │ │ ├── migrate │ │ │ ├── bridge.ts │ │ │ ├── nitro.ts │ │ │ └── protocol.ts │ │ ├── test-upgrade.ts │ │ └── verify │ │ │ ├── defender.ts │ │ │ ├── sourcify.ts │ │ │ └── verify.ts │ ├── test │ │ ├── e2e │ │ │ ├── deployment │ │ │ │ ├── config │ │ │ │ │ ├── allocationExchange.test.ts │ │ │ │ │ ├── controller.test.ts │ │ │ │ │ ├── disputeManager.test.ts │ │ │ │ │ ├── epochManager.test.ts │ │ │ │ │ ├── gns.test.ts │ │ │ │ │ ├── graphProxyAdmin.test.ts │ │ │ │ │ ├── graphToken.test.ts │ │ │ │ │ ├── l1 │ │ │ │ │ │ ├── bridgeEscrow.test.ts │ │ │ │ │ │ ├── curation.test.ts │ │ │ │ │ │ ├── graphToken.test.ts │ │ │ │ │ │ ├── l1GNS.test.ts │ │ │ │ │ │ ├── l1GraphTokenGateway.test.ts │ │ │ │ │ │ ├── l1Staking.test.ts │ │ │ │ │ │ └── rewardsManager.test.ts │ │ │ │ │ ├── l2 │ │ │ │ │ │ ├── l2Curation.test.ts │ │ │ │ │ │ ├── l2GNS.test.ts │ │ │ │ │ │ ├── l2GraphToken.test.ts │ │ │ │ │ │ ├── l2GraphTokenGateway.test.ts │ │ │ │ │ │ ├── l2Staking.test.ts │ │ │ │ │ │ └── rewardsManager.test.ts │ │ │ │ │ ├── rewardsManager.test.ts │ │ │ │ │ ├── serviceRegistry.test..ts │ │ │ │ │ ├── staking.test.ts │ │ │ │ │ └── subgraphNFT.test.ts │ │ │ │ └── init │ │ │ │ │ ├── allocationExchange.test.ts │ │ │ │ │ ├── gns.test.ts │ │ │ │ │ ├── l1 │ │ │ │ │ ├── bridgeEscrow.test.ts │ │ │ │ │ └── graphToken.test.ts │ │ │ │ │ └── l2 │ │ │ │ │ └── graphToken.test.ts │ │ │ ├── scenarios │ │ │ │ ├── close-allocations.test.ts │ │ │ │ ├── close-allocations.ts │ │ │ │ ├── create-subgraphs.test.ts │ │ │ │ ├── create-subgraphs.ts │ │ │ │ ├── fixtures │ │ │ │ │ ├── bridge.ts │ │ │ │ │ ├── curators.ts │ │ │ │ │ ├── indexers.ts │ │ │ │ │ └── subgraphs.ts │ │ │ │ ├── open-allocations.test.ts │ │ │ │ ├── open-allocations.ts │ │ │ │ ├── send-grt-to-l2.test.ts │ │ │ │ └── send-grt-to-l2.ts │ │ │ └── upgrades │ │ │ │ ├── example │ │ │ │ ├── Instructions.md │ │ │ │ ├── post-upgrade.test.ts │ │ │ │ ├── post-upgrade.ts │ │ │ │ ├── pre-upgrade.test.ts │ │ │ │ └── pre-upgrade.ts │ │ │ │ └── exponential-rebates │ │ │ │ ├── Instructions.md │ │ │ │ ├── abis │ │ │ │ └── staking.ts │ │ │ │ ├── fixtures │ │ │ │ ├── allocations.ts │ │ │ │ └── indexers.ts │ │ │ │ ├── post-upgrade.test.ts │ │ │ │ ├── post-upgrade.ts │ │ │ │ ├── pre-upgrade.test.ts │ │ │ │ └── pre-upgrade.ts │ │ └── unit │ │ │ ├── curation │ │ │ ├── configuration.test.ts │ │ │ └── curation.test.ts │ │ │ ├── disputes │ │ │ ├── common.ts │ │ │ ├── configuration.test.ts │ │ │ ├── poi.test.ts │ │ │ └── query.test.ts │ │ │ ├── epochs.test.ts │ │ │ ├── gateway │ │ │ ├── bridgeEscrow.test.ts │ │ │ └── l1GraphTokenGateway.test.ts │ │ │ ├── gns.test.ts │ │ │ ├── governance │ │ │ ├── controller.test.ts │ │ │ ├── governed.test.ts │ │ │ └── pausing.test.ts │ │ │ ├── graphToken.test.ts │ │ │ ├── l2 │ │ │ ├── l2ArbitrumMessengerMock.ts │ │ │ ├── l2Curation.test.ts │ │ │ ├── l2GNS.test.ts │ │ │ ├── l2GraphToken.test.ts │ │ │ ├── l2GraphTokenGateway.test.ts │ │ │ └── l2Staking.test.ts │ │ │ ├── lib │ │ │ ├── fixtures.ts │ │ │ ├── gnsUtils.ts │ │ │ └── graphTokenTests.ts │ │ │ ├── payments │ │ │ └── allocationExchange.test.ts │ │ │ ├── rewards │ │ │ ├── rewards.test.ts │ │ │ └── subgraphAvailability.test.ts │ │ │ ├── serviceRegisty.test.ts │ │ │ ├── staking │ │ │ ├── allocation.test.ts │ │ │ ├── configuration.test.ts │ │ │ ├── delegation.test.ts │ │ │ ├── l2Transfer.test.ts │ │ │ ├── rebate.test.ts │ │ │ └── staking.test.ts │ │ │ └── upgrade │ │ │ └── admin.test.ts │ ├── truffle.js │ └── tsconfig.json ├── data-edge │ ├── .env.sample │ ├── .markdownlint.json │ ├── .solcover.js │ ├── LICENSE │ ├── README.md │ ├── addresses.json │ ├── contracts │ │ ├── DataEdge.sol │ │ └── EventfulDataEdge.sol │ ├── hardhat.config.ts │ ├── package.json │ ├── prettier.config.cjs │ ├── scripts │ │ ├── build │ │ ├── coverage │ │ ├── flatten │ │ ├── prepublish │ │ ├── security │ │ └── test │ ├── tasks │ │ ├── craft-calldata.ts │ │ ├── deploy.ts │ │ └── post-calldata.ts │ ├── test │ │ ├── dataedge.test.ts │ │ └── eventful-dataedge.test.ts │ └── tsconfig.json ├── sdk │ ├── .markdownlint.json │ ├── .mocharc.json │ ├── CHANGELOG.md │ ├── package.json │ ├── prettier.config.cjs │ ├── src │ │ ├── chain │ │ │ ├── id.ts │ │ │ ├── index.ts │ │ │ ├── list.ts │ │ │ ├── name.ts │ │ │ └── types.ts │ │ ├── deployments │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── address-book.ts │ │ │ │ ├── config.ts │ │ │ │ ├── contracts │ │ │ │ │ ├── load.ts │ │ │ │ │ ├── log.ts │ │ │ │ │ └── wrap.ts │ │ │ │ ├── deploy │ │ │ │ │ ├── artifacts.ts │ │ │ │ │ ├── contract.ts │ │ │ │ │ ├── deploy.ts │ │ │ │ │ └── factory.ts │ │ │ │ └── types │ │ │ │ │ ├── address-book.ts │ │ │ │ │ ├── artifacts.ts │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── contract.ts │ │ │ │ │ └── deploy.ts │ │ │ ├── logger.ts │ │ │ └── network │ │ │ │ ├── actions │ │ │ │ ├── bridge-config.ts │ │ │ │ ├── bridge-to-l1.ts │ │ │ │ ├── bridge-to-l2.ts │ │ │ │ ├── disputes.ts │ │ │ │ ├── gns.ts │ │ │ │ ├── governed.ts │ │ │ │ ├── graph-token.ts │ │ │ │ ├── pause.ts │ │ │ │ ├── staking.ts │ │ │ │ └── types.ts │ │ │ │ └── deployment │ │ │ │ ├── address-book.ts │ │ │ │ ├── config.ts │ │ │ │ └── contracts │ │ │ │ ├── deploy.ts │ │ │ │ ├── list.ts │ │ │ │ ├── load.ts │ │ │ │ └── proxy.ts │ │ ├── gre │ │ │ ├── README.md │ │ │ ├── accounts.ts │ │ │ ├── config.ts │ │ │ ├── gre.ts │ │ │ ├── helpers │ │ │ │ ├── argv.ts │ │ │ │ ├── error.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── network.ts │ │ │ │ └── utils.ts │ │ │ ├── index.ts │ │ │ ├── providers.ts │ │ │ ├── task.ts │ │ │ ├── test │ │ │ │ ├── accounts.test.ts │ │ │ │ ├── config.test.ts │ │ │ │ ├── files │ │ │ │ │ ├── addresses-hre.json │ │ │ │ │ ├── addresses-opts.json │ │ │ │ │ └── config │ │ │ │ │ │ ├── graph.arbitrum-goerli.yml │ │ │ │ │ │ ├── graph.arbitrum-hre.yml │ │ │ │ │ │ ├── graph.arbitrum-opts.yml │ │ │ │ │ │ ├── graph.goerli.yml │ │ │ │ │ │ ├── graph.hre.yml │ │ │ │ │ │ ├── graph.mainnet.yml │ │ │ │ │ │ ├── graph.opts.yml │ │ │ │ │ │ └── graph.opts2.yml │ │ │ │ ├── fixture-projects │ │ │ │ │ ├── default-config │ │ │ │ │ │ └── hardhat.config.ts │ │ │ │ │ ├── graph-config-bad │ │ │ │ │ │ └── hardhat.config.ts │ │ │ │ │ ├── graph-config-desambiguate │ │ │ │ │ │ └── hardhat.config.ts │ │ │ │ │ ├── graph-config-full │ │ │ │ │ │ └── hardhat.config.ts │ │ │ │ │ └── graph-config │ │ │ │ │ │ ├── .accounts │ │ │ │ │ │ ├── test-account-l2.json │ │ │ │ │ │ └── test-account.json │ │ │ │ │ │ └── hardhat.config.ts │ │ │ │ ├── gre.test.ts │ │ │ │ └── helpers.ts │ │ │ ├── type-extensions.ts │ │ │ └── types.ts │ │ ├── helpers │ │ │ ├── arbitrum.ts │ │ │ ├── balance.ts │ │ │ ├── code.ts │ │ │ ├── epoch.ts │ │ │ ├── impersonate.ts │ │ │ ├── index.ts │ │ │ ├── mine.ts │ │ │ ├── snapshot.ts │ │ │ └── time.ts │ │ ├── index.ts │ │ └── utils │ │ │ ├── abi.ts │ │ │ ├── address.ts │ │ │ ├── allocation.ts │ │ │ ├── arbitrum │ │ │ ├── address.ts │ │ │ ├── gas.ts │ │ │ ├── index.ts │ │ │ └── message.ts │ │ │ ├── assertions.ts │ │ │ ├── bytes.ts │ │ │ ├── eip712.ts │ │ │ ├── hash.ts │ │ │ ├── index.ts │ │ │ ├── nonce.ts │ │ │ ├── prompt.ts │ │ │ ├── subgraph.ts │ │ │ ├── time.ts │ │ │ ├── type-guard.ts │ │ │ └── units.ts │ └── tsconfig.json └── token-distribution │ ├── .env.sample │ ├── .graphclientrc.yml │ ├── .markdownlint.json │ ├── .openzeppelin │ ├── goerli.json │ ├── mainnet.json │ ├── unknown-11155111.json │ ├── unknown-42161.json │ ├── unknown-421613.json │ └── unknown-421614.json │ ├── .solcover.js │ ├── DEPLOYMENT.md │ ├── LICENSE.md │ ├── README.md │ ├── abi │ ├── TokenLockWalletABIFull.json │ └── TokenLockWalletABIRemix.json │ ├── audits │ └── 2020-11-graph-token-distribution.pdf │ ├── contracts │ ├── GraphTokenDistributor.sol │ ├── GraphTokenLock.sol │ ├── GraphTokenLockManager.sol │ ├── GraphTokenLockSimple.sol │ ├── GraphTokenLockWallet.sol │ ├── ICallhookReceiver.sol │ ├── IGraphTokenLock.sol │ ├── IGraphTokenLockManager.sol │ ├── L1GraphTokenLockTransferTool.sol │ ├── L2GraphTokenLockManager.sol │ ├── L2GraphTokenLockTransferTool.sol │ ├── L2GraphTokenLockWallet.sol │ ├── MathUtils.sol │ ├── MinimalProxyFactory.sol │ ├── Ownable.sol │ ├── arbitrum │ │ └── ITokenGateway.sol │ └── tests │ │ ├── BridgeMock.sol │ │ ├── GraphTokenMock.sol │ │ ├── InboxMock.sol │ │ ├── L1TokenGatewayMock.sol │ │ ├── L2TokenGatewayMock.sol │ │ ├── Stakes.sol │ │ ├── StakingMock.sol │ │ ├── WalletMock.sol │ │ └── arbitrum │ │ ├── AddressAliasHelper.sol │ │ ├── IBridge.sol │ │ ├── IInbox.sol │ │ └── IMessageProvider.sol │ ├── deploy │ ├── 1_test.ts │ ├── 2_l1_manager_wallet.ts │ ├── 3_l2_wallet.ts │ ├── 4_l1_transfer_tool.ts │ ├── 5_l2_manager.ts │ ├── 6_l2_transfer_tool.ts │ └── lib │ │ └── utils.ts │ ├── deployments │ ├── arbitrum-goerli │ │ ├── .chainId │ │ ├── L2GraphTokenLockManager-Testnet.json │ │ ├── L2GraphTokenLockTransferTool.json │ │ ├── L2GraphTokenLockWallet.json │ │ └── solcInputs │ │ │ └── b5cdad58099d39cd1aed000b2fd864d8.json │ ├── arbitrum-one │ │ ├── .chainId │ │ ├── L2GraphTokenLockManager-Foundation-v1.json │ │ ├── L2GraphTokenLockManager-MIPs.json │ │ ├── L2GraphTokenLockManager.json │ │ ├── L2GraphTokenLockTransferTool.json │ │ ├── L2GraphTokenLockWallet.json │ │ └── solcInputs │ │ │ └── b5cdad58099d39cd1aed000b2fd864d8.json │ ├── arbitrum-sepolia │ │ ├── .chainId │ │ ├── L2GraphTokenLockManager.json │ │ ├── L2GraphTokenLockTransferTool.json │ │ ├── L2GraphTokenLockWallet.json │ │ └── solcInputs │ │ │ └── 095bd30babc75057be19228ca1fd7aa4.json │ ├── goerli │ │ ├── .chainId │ │ ├── GraphTokenLockManager-Testnet.json │ │ ├── GraphTokenLockManager.json │ │ ├── GraphTokenLockWallet-Testnet.json │ │ ├── GraphTokenLockWallet.json │ │ ├── L1GraphTokenLockTransferTool.json │ │ └── solcInputs │ │ │ ├── 3c1e469b4f9ba208577ab7c230900006.json │ │ │ └── b5cdad58099d39cd1aed000b2fd864d8.json │ ├── mainnet │ │ ├── .chainId │ │ ├── GraphTokenLockManager-Foundation.json │ │ ├── GraphTokenLockManager-MIPs.json │ │ ├── GraphTokenLockManager-Migrations.json │ │ ├── GraphTokenLockManager.json │ │ ├── GraphTokenLockWallet-Foundation.json │ │ ├── GraphTokenLockWallet-MIPs.json │ │ ├── GraphTokenLockWallet-Migrations.json │ │ ├── GraphTokenLockWallet.json │ │ ├── L1GraphTokenLockTransferTool.json │ │ └── solcInputs │ │ │ ├── 5ad03e035f8e3c63878532d87a315ef8.json │ │ │ ├── 6f5e8f450f52dd96ebb796aa6620fee9.json │ │ │ ├── a72ab6278ade6c5c10115f7be2c555c9.json │ │ │ ├── b5cdad58099d39cd1aed000b2fd864d8.json │ │ │ └── f0757d7c1c560a6ae9697525709a3f5b.json │ ├── rinkeby │ │ ├── .chainId │ │ ├── GraphTokenLockManager.json │ │ ├── GraphTokenLockWallet.json │ │ ├── GraphTokenMock.json │ │ └── solcInputs │ │ │ └── a72ab6278ade6c5c10115f7be2c555c9.json │ └── sepolia │ │ ├── .chainId │ │ ├── GraphTokenLockManager.json │ │ ├── GraphTokenLockWallet.json │ │ ├── L1GraphTokenLockTransferTool.json │ │ └── solcInputs │ │ └── 095bd30babc75057be19228ca1fd7aa4.json │ ├── hardhat.config.ts │ ├── ops │ ├── beneficiary.ts │ ├── create.ts │ ├── delete.ts │ ├── deploy-data.csv │ ├── info.ts │ ├── manager.ts │ ├── queries │ │ ├── account.graphql │ │ ├── curators.graphql │ │ ├── network.graphql │ │ └── tokenLockWallets.graphql │ ├── results.csv │ ├── tx-builder-template.json │ └── tx-builder.ts │ ├── package.json │ ├── prettier.config.cjs │ ├── scripts │ ├── build │ ├── build.js │ ├── coverage │ ├── flatten │ ├── prepublish │ ├── security │ └── test │ ├── test │ ├── config.ts │ ├── distributor.test.ts │ ├── l1TokenLockTransferTool.test.ts │ ├── l2TokenLockManager.test.ts │ ├── l2TokenLockTransferTool.test.ts │ ├── network.ts │ ├── tokenLock.test.ts │ └── tokenLockWallet.test.ts │ └── tsconfig.json ├── prettier.config.cjs ├── scripts ├── count-changes └── set-json-key-value ├── tsconfig.json └── yarn.lock /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/smooth-balloons-stare.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@graphprotocol/contracts": patch 3 | --- 4 | 5 | make sdk and console table printer a dev dep 6 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graph contracts", 3 | "dockerComposeFile": ["docker-compose.yml"], 4 | "service": "dev-graph-contracts", 5 | "features": { 6 | "ghcr.io/devcontainers/features/git:1": { 7 | "configureGitHubCLI": true, 8 | "gitCredentialHelper": "cache" 9 | }, 10 | "ghcr.io/devcontainers/features/github-cli:1": {}, 11 | "ghcr.io/devcontainers/features/common-utils:2.5.3": {}, 12 | "ghcr.io/devcontainers/features/node:1": { 13 | "version": "20" 14 | }, 15 | "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} 16 | }, 17 | "postCreateCommand": ".devcontainer/project-setup.sh", 18 | "remoteUser": "vscode", 19 | "workspaceFolder": "${localWorkspaceFolder}", 20 | "customizations": { 21 | "vscode": { 22 | "extensions": [ 23 | "rust-lang.rust-analyzer", 24 | "tamasfe.even-better-toml", 25 | "usernamehw.errorlens", 26 | "yzhang.markdown-all-in-one", 27 | "DavidAnson.vscode-markdownlint", 28 | "shd101wyy.markdown-preview-enhanced", 29 | "bierner.markdown-preview-github-styles", 30 | "Gruntfuggly.todo-tree", 31 | "ms-azuretools.vscode-docker", 32 | "donjayamanne.githistory", 33 | "eamodio.gitlens", 34 | "fill-labs.dependi", 35 | "streetsidesoftware.code-spell-checker", 36 | "Augment.vscode-augment", 37 | "NomicFoundation.hardhat-solidity", 38 | "foundry-rs.foundry-vscode" 39 | ] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | dev-graph-contracts: 3 | build: 4 | context: . 5 | dockerfile: Dockerfile 6 | env_file: 7 | - /opt/configs/graphprotocol/contracts.env 8 | environment: 9 | # Essential for large builds 10 | - NODE_OPTIONS=--max-old-space-size=4096 11 | 12 | # Clean development environment 13 | - PYTHONDONTWRITEBYTECODE=1 14 | 15 | # Disable interactive prompts 16 | - COREPACK_ENABLE_DOWNLOAD_PROMPT=0 17 | 18 | # Standard user directories 19 | - XDG_CACHE_HOME=/home/vscode/.cache 20 | - XDG_CONFIG_HOME=/home/vscode/.config 21 | - XDG_DATA_HOME=/home/vscode/.local/share 22 | 23 | # Safe caches (won't cause cross-branch issues) 24 | - GH_CONFIG_DIR=/home/vscode/.cache/github 25 | - PIP_CACHE_DIR=/home/vscode/.cache/pip 26 | 27 | # Note: NPM, Yarn, Foundry, and Solidity caches are intentionally not set 28 | # to avoid cross-branch contamination. Tools will use their default locations. 29 | volumes: 30 | # Git repo root 31 | - /git:/git 32 | 33 | # Local directories for user data (keep local to container) 34 | - vscode-cache:/home/vscode/.cache 35 | - vscode-config:/home/vscode/.config 36 | - vscode-data:/home/vscode/.local/share 37 | - vscode-bin:/home/vscode/.local/bin 38 | 39 | # Shared pnpm cache (safe due to content-addressable storage) 40 | - pnpm-store:/home/vscode/.local/share/pnpm 41 | - pnpm-cache:/home/vscode/.cache/pnpm 42 | 43 | volumes: 44 | vscode-cache: 45 | vscode-config: 46 | vscode-data: 47 | vscode-bin: 48 | pnpm-store: 49 | pnpm-cache: 50 | -------------------------------------------------------------------------------- /.devcontainer/host-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Host setup script for Graph Protocol Contracts dev container 3 | # Run this script on the host before starting the dev container 4 | # Usage: sudo .devcontainer/host-setup.sh 5 | 6 | set -euo pipefail 7 | 8 | echo "Setting up host environment for Graph Protocol Contracts dev container..." 9 | 10 | # Check if running as root 11 | if [ "$(id -u)" -ne 0 ]; then 12 | echo "Error: This script must be run as root (sudo)" >&2 13 | exit 1 14 | fi 15 | 16 | CACHE_DIRS=( 17 | "/cache/vscode-cache" 18 | "/cache/vscode-config" 19 | "/cache/vscode-data" 20 | "/cache/vscode-bin" 21 | "/cache/hardhat" 22 | "/cache/npm" 23 | "/cache/yarn" 24 | "/cache/pip" 25 | "/cache/pycache" 26 | "/cache/solidity" 27 | "/cache/foundry" 28 | "/cache/github" 29 | "/cache/apt" 30 | "/cache/apt-lib" 31 | ) 32 | 33 | echo "Creating cache directories..." 34 | for dir in "${CACHE_DIRS[@]}"; do 35 | if [ ! -d "$dir" ]; then 36 | echo "Creating $dir" 37 | mkdir -p "$dir" 38 | chmod 777 "$dir" 39 | else 40 | echo "$dir already exists" 41 | fi 42 | done 43 | 44 | # Note: Package-specific directories will be created by the project-setup.sh script 45 | # inside the container, as they are tied to the project structure 46 | 47 | echo "Host setup completed successfully!" 48 | echo "You can now start or rebuild your dev container." 49 | -------------------------------------------------------------------------------- /.devcontainer/sample-graph.env: -------------------------------------------------------------------------------- 1 | # Sample environment file for Graph Protocol contracts development 2 | # Copy the Git settings below to your actual environment file at: 3 | # /opt/configs/graphprotocol/contracts.env 4 | 5 | # Git settings for commit signing 6 | # Add these settings if you want to enable Git commit signing 7 | GIT_USER_NAME=Your Name 8 | GIT_USER_EMAIL=your.email@example.com 9 | 10 | # Custom binary path 11 | # Add this setting if you want to add a custom binary path to the PATH inside the container 12 | # CONTAINER_BIN_PATH=/path/to/your/binaries 13 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | 3 | runs: 4 | using: composite 5 | 6 | steps: 7 | - name: Install system dependencies 8 | shell: bash 9 | run: | 10 | sudo apt-get update 11 | sudo apt-get install -y libudev-dev libusb-1.0-0-dev 12 | - name: Enable corepack for modern yarn 13 | shell: bash 14 | run: corepack enable 15 | - name: Install Node.js 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 20 19 | cache: 'yarn' 20 | - name: Install dependencies 21 | shell: bash 22 | run: yarn --immutable 23 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | env: 4 | CI: true 5 | STUDIO_API_KEY: ${{ secrets.STUDIO_API_KEY }} 6 | 7 | on: 8 | push: 9 | branches: "*" 10 | pull_request: 11 | branches: "*" 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | - name: Set up environment 21 | uses: ./.github/actions/setup 22 | - name: Build 23 | run: yarn build || yarn build -------------------------------------------------------------------------------- /.github/workflows/ci-contracts.yml: -------------------------------------------------------------------------------- 1 | name: CI - packages/contracts 2 | 3 | env: 4 | CI: true 5 | 6 | on: 7 | push: 8 | branches: '*' 9 | paths: 10 | - packages/contracts/** 11 | pull_request: 12 | branches: '*' 13 | paths: 14 | - packages/contracts/** 15 | workflow_dispatch: 16 | 17 | jobs: 18 | test-ci: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | - name: Set up environment 24 | uses: ./.github/actions/setup 25 | - name: Build dependencies 26 | run: | 27 | pushd packages/contracts 28 | yarn build 29 | popd 30 | pushd packages/sdk 31 | yarn build 32 | - name: Run tests 33 | run: | 34 | pushd packages/contracts 35 | yarn test:coverage 36 | - name: Upload coverage report 37 | uses: codecov/codecov-action@v3 38 | with: 39 | token: ${{ secrets.CODECOV_TOKEN }} 40 | files: ./packages/contracts/coverage.json 41 | flags: unittests 42 | name: graphprotocol-contracts 43 | fail_ci_if_error: true 44 | -------------------------------------------------------------------------------- /.github/workflows/ci-data-edge.yml: -------------------------------------------------------------------------------- 1 | name: CI - packages/data-edge 2 | 3 | env: 4 | CI: true 5 | 6 | on: 7 | push: 8 | branches: '*' 9 | paths: 10 | - packages/data-edge/** 11 | pull_request: 12 | branches: '*' 13 | paths: 14 | - packages/data-edge/** 15 | workflow_dispatch: 16 | 17 | jobs: 18 | test-ci: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | - name: Set up environment 24 | uses: ./.github/actions/setup 25 | - name: Build 26 | run: | 27 | pushd packages/data-edge 28 | yarn build 29 | - name: Run tests 30 | run: | 31 | pushd packages/data-edge 32 | yarn test 33 | -------------------------------------------------------------------------------- /.github/workflows/ci-token-dist.yml: -------------------------------------------------------------------------------- 1 | name: CI - packages/token-distribution 2 | 3 | env: 4 | CI: true 5 | STUDIO_API_KEY: ${{ secrets.STUDIO_API_KEY }} 6 | 7 | on: 8 | push: 9 | branches: '*' 10 | paths: 11 | - packages/token-distribution/** 12 | pull_request: 13 | branches: '*' 14 | paths: 15 | - packages/token-distribution/** 16 | workflow_dispatch: 17 | 18 | jobs: 19 | test-ci: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | - name: Set up environment 25 | uses: ./.github/actions/setup 26 | - name: Build contracts (dependency) 27 | run: | 28 | pushd packages/contracts 29 | yarn build 30 | - name: Build 31 | run: | 32 | pushd packages/token-distribution 33 | yarn build 34 | - name: Run tests 35 | run: | 36 | pushd packages/token-distribution 37 | yarn test 38 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | package: 7 | description: 'Package to publish' 8 | required: true 9 | type: choice 10 | options: 11 | - contracts 12 | - sdk 13 | tag: 14 | description: 'Tag to publish' 15 | required: true 16 | type: string 17 | default: latest 18 | 19 | jobs: 20 | publish: 21 | name: Publish package 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | - name: Set up environment 27 | uses: ./.github/actions/setup 28 | - name: Publish 🚀 29 | shell: bash 30 | run: | 31 | pushd packages/${{ inputs.package }} 32 | yarn npm publish --tag ${{ inputs.tag }} --access public 33 | env: 34 | YARN_NPM_AUTH_TOKEN: ${{ secrets.GRAPHPROTOCOL_NPM_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | yarn-debug.log* 3 | yarn-error.log* 4 | 5 | # Dependency directories 6 | node_modules/ 7 | forge-std/ 8 | 9 | # Yarn 10 | .yarn/* 11 | !.yarn/patches 12 | !.yarn/plugins 13 | !.yarn/releases 14 | !.yarn/sdks 15 | !.yarn/versions 16 | 17 | # Hardhat artifacts 18 | artifacts/ 19 | cache/ 20 | cached/ 21 | cache 22 | 23 | # ESLint cache 24 | .eslintcache 25 | packages/*/.eslintcache 26 | 27 | # Build artifacts 28 | dist/ 29 | build/ 30 | typechain/ 31 | typechain-types/ 32 | deployments/hardhat/ 33 | 34 | # Ignore solc bin output 35 | bin/ 36 | 37 | # Others 38 | .env 39 | .DS_Store 40 | .vscode 41 | 42 | # Coverage and other reports 43 | coverage/ 44 | reports/ 45 | coverage.json 46 | lcov.info 47 | 48 | # Local test files 49 | addresses-local.json 50 | localNetwork.json 51 | arbitrum-addresses-local.json 52 | tx-*.log 53 | addresses-fork.json 54 | 55 | # Keys 56 | .keystore 57 | 58 | # Forge artifacts 59 | cache_forge 60 | forge-artifacts/ 61 | packages/issuance/lib/forge-std/ 62 | 63 | # Graph client 64 | .graphclient 65 | 66 | tx-builder-*.json 67 | !tx-builder-template.json 68 | 69 | # Hardhat Ignition 70 | **/chain-31337/ 71 | **/chain-1377/ 72 | **/horizon-localhost/ 73 | **/horizon-hardhat/ 74 | **/subgraph-service-localhost/ 75 | **/subgraph-service-hardhat/ 76 | !**/ignition/**/artifacts/ 77 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no-install commitlint --edit "" 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | npx lint-staged 4 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD013": false, 4 | "MD024": { "siblings_only": true }, 5 | "MD033": false, 6 | "MD029": { "style": "ordered" }, 7 | "MD007": { "indent": 2 }, 8 | "MD004": { "style": "dash" } 9 | } 10 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "plugins": ["prettier"], 4 | "rules": { 5 | "func-visibility": ["warn", { "ignoreConstructors": true }], 6 | "compiler-version": ["off"], 7 | "constructor-syntax": "warn", 8 | "quotes": ["error", "double"], 9 | "reason-string": ["off"], 10 | "not-rely-on-time": "off", 11 | "no-empty-blocks": "off" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: 6 | max: 120 7 | level: warning 8 | indentation: 9 | spaces: 2 10 | indent-sequences: true 11 | truthy: 12 | allowed-values: ['true', 'false', 'yes', 'no'] 13 | document-start: 14 | present: true 15 | document-end: 16 | present: false 17 | comments: 18 | min-spaces-from-content: 1 19 | braces: 20 | min-spaces-inside: 0 21 | max-spaces-inside: 1 22 | brackets: 23 | min-spaces-inside: 0 24 | max-spaces-inside: 1 25 | commas: 26 | max-spaces-before: 0 27 | min-spaces-after: 1 28 | max-spaces-after: 1 29 | 30 | ignore: | 31 | node_modules/ 32 | dist/ 33 | build/ 34 | cache/ 35 | coverage/ 36 | .yarn/ 37 | packages/ 38 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] } 2 | -------------------------------------------------------------------------------- /packages/contracts/.env.example: -------------------------------------------------------------------------------- 1 | MNEMONIC= 2 | ETHERSCAN_API_KEY= 3 | ARBISCAN_API_KEY= 4 | INFURA_KEY= 5 | ADDRESS_BOOK="addresses.json" 6 | GRAPH_CONFIG="config/graph.mainnet.yml" 7 | PROVIDER_URL="http://127.0.0.1:8545" -------------------------------------------------------------------------------- /packages/contracts/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.markdownlint.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/contracts/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register/files", 3 | "ignore": ["test/fixture-projects/**/*"], 4 | "timeout": 6000 5 | } 6 | -------------------------------------------------------------------------------- /packages/contracts/.solcover.js: -------------------------------------------------------------------------------- 1 | const skipFiles = ['bancor', 'ens', 'erc1056', 'arbitrum', 'tests/arbitrum'] 2 | 3 | module.exports = { 4 | providerOptions: { 5 | mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', 6 | network_id: 1337, 7 | }, 8 | skipFiles, 9 | istanbulFolder: './reports/coverage', 10 | configureYulOptimizer: true, 11 | mocha: { 12 | grep: '@skip-on-coverage', 13 | invert: true, 14 | }, 15 | onCompileComplete: async function (/* config */) { 16 | // Set environment variable to indicate we're running under coverage 17 | process.env.SOLIDITY_COVERAGE = 'true' 18 | }, 19 | onIstanbulComplete: async function (/* config */) { 20 | // Clean up environment variable 21 | delete process.env.SOLIDITY_COVERAGE 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /packages/contracts/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @graphprotocol/contracts 2 | 3 | ## 6.3.0 4 | 5 | ### Minor Changes 6 | 7 | - Remove restriction that prevented closing allocations older than 1 epoch. 8 | 9 | ## 6.2.1 10 | 11 | ### Patch Changes 12 | 13 | - Round up when calculating curation tax 14 | - Round up when calculating consecutive stake thawing periods 15 | 16 | ## 6.2.0 17 | 18 | ### Minor Changes 19 | 20 | - Update implementation addresses with GGP 31, 34 and 35 21 | 22 | ### Patch Changes 23 | 24 | - 554af2c: feat(utils): add utility to parse subgraph ids 25 | - Updated dependencies [554af2c] 26 | - Updated dependencies [c5641c5] 27 | - @graphprotocol/sdk@0.5.0 28 | 29 | ## 6.1.3 30 | 31 | ### Patch Changes 32 | 33 | - Ensure globbing is enabled in prepack 34 | 35 | ## 6.1.2 36 | 37 | ### Patch Changes 38 | 39 | - Correctly pass ts file list to tsc in prepack 40 | 41 | ## 6.1.1 42 | 43 | ### Patch Changes 44 | 45 | - Use prepack to correctly prepare outputs for the published package 46 | 47 | ## 6.1.0 48 | 49 | ### Minor Changes 50 | 51 | - Introduce changesets for versioning 52 | - Add new staging implementations including GGPs 31, 34 and 35 53 | - Add new testnet implementations including GGPs 31, 34 and 35 54 | 55 | ### Patch Changes 56 | 57 | - Fixes for verifyAll and bridge:send-to-l2 hardhat tasks 58 | -------------------------------------------------------------------------------- /packages/contracts/arbitrum-addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "https://developer.offchainlabs.com/docs/useful_addresses", 3 | "1": { 4 | "L1GatewayRouter": { 5 | "address": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef" 6 | }, 7 | "IInbox": { 8 | "address": "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f" 9 | } 10 | }, 11 | "4": { 12 | "L1GatewayRouter": { 13 | "address": "0x70C143928eCfFaf9F5b406f7f4fC28Dc43d68380" 14 | }, 15 | "IInbox": { 16 | "address": "0x578BAde599406A8fE3d24Fd7f7211c0911F5B29e" 17 | } 18 | }, 19 | "5": { 20 | "L1GatewayRouter": { 21 | "address": "0x4c7708168395aEa569453Fc36862D2ffcDaC588c" 22 | }, 23 | "IInbox": { 24 | "address": "0x6BEbC4925716945D46F0Ec336D5C2564F419682C" 25 | } 26 | }, 27 | "42161": { 28 | "L2GatewayRouter": { 29 | "address": "0x5288c571Fd7aD117beA99bF60FE0846C4E84F933" 30 | } 31 | }, 32 | "421611": { 33 | "L2GatewayRouter": { 34 | "address": "0x9413AD42910c1eA60c737dB5f58d1C504498a3cD" 35 | } 36 | }, 37 | "421613": { 38 | "L2GatewayRouter": { 39 | "address": "0xE5B9d8d42d656d1DcB8065A6c012FE3780246041" 40 | } 41 | }, 42 | "421614": { 43 | "L2GatewayRouter": { 44 | "address": "0x9fDD1C4E4AA24EEc1d913FABea925594a20d43C7" 45 | } 46 | }, 47 | "11155111": { 48 | "L1GatewayRouter": { 49 | "address": "0xcE18836b233C83325Cc8848CA4487e94C6288264" 50 | }, 51 | "IInbox": { 52 | "address": "0xaAe29B0366299461418F5324a79Afc425BE5ae21" 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/contracts/audits/ConsenSysDiligence/2021-05-graph-initial-review.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/ConsenSysDiligence/2021-05-graph-initial-review.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/ConsenSysDiligence/2021-08-staking-multicall-and-delegation-fixes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/ConsenSysDiligence/2021-08-staking-multicall-and-delegation-fixes.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/ConsenSysDiligence/2022-01-graph-pr527-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/ConsenSysDiligence/2022-01-graph-pr527-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/ConsenSysDiligence/2022-03-graph-altruistic-alloc-and-query-versioning.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/ConsenSysDiligence/2022-03-graph-altruistic-alloc-and-query-versioning.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2020-08-graph-protocol.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2020-08-graph-protocol.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-addresses-cache-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-addresses-cache-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-governance-upgrade-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-governance-upgrade-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-rewardsmanager-upgrade-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-rewardsmanager-upgrade-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-slashing-upgrade-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-slashing-upgrade-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-staking-bugfix-2-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-staking-bugfix-2-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-04-graph-staking-bugfix-audit-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-04-graph-staking-bugfix-audit-1.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-08-graph-gns-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-08-graph-gns-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-11-graph-curation-minimal-proxy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-11-graph-curation-minimal-proxy.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-11-graph-gns-transferrable-owner.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-11-graph-gns-transferrable-owner.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2021-12-graph-rewards-signal-threshold.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2021-12-graph-rewards-signal-threshold.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-07-graph-arbitrum-bridge-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-07-graph-arbitrum-bridge-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-07-pr552-summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-07-pr552-summary.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-07-pr568-summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-07-pr568-summary.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-07-pr569-summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-07-pr569-summary.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-07-pr571-summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-07-pr571-summary.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2022-09-graph-drip-keeper-reward-audit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2022-09-graph-drip-keeper-reward-audit.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2023-05-staking-vesting-l2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2023-05-staking-vesting-l2.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2023-06-graph-exponential-rebates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2023-06-graph-exponential-rebates.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2023-08-dispute-manager-status.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2023-08-dispute-manager-status.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2023-11-permissionless-payers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2023-11-permissionless-payers.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2023-11-remove-delegation-parameters-cooldown.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2023-11-remove-delegation-parameters-cooldown.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2024-02-graph-availability-manager-minimum-allocation-removal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2024-02-graph-availability-manager-minimum-allocation-removal.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/OpenZeppelin/2024-02-subgraph-availability-manager-and-minimum-allocation-duration-removal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/OpenZeppelin/2024-02-subgraph-availability-manager-and-minimum-allocation-duration-removal.pdf -------------------------------------------------------------------------------- /packages/contracts/audits/Trust/2023-02-operator-decentralization-pr749.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/contracts/audits/Trust/2023-02-operator-decentralization-pr749.pdf -------------------------------------------------------------------------------- /packages/contracts/contracts/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /packages/contracts/contracts/arbitrum/IMessageProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | /* 4 | * Copyright 2021, Offchain Labs, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Originally copied from: 19 | * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth 20 | * 21 | * MODIFIED from Offchain Labs' implementation: 22 | * - Changed solidity version to 0.7.6 (pablo@edgeandnode.com) 23 | * 24 | */ 25 | 26 | pragma solidity ^0.7.6; 27 | 28 | interface IMessageProvider { 29 | event InboxMessageDelivered(uint256 indexed messageNum, bytes data); 30 | 31 | event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); 32 | } 33 | -------------------------------------------------------------------------------- /packages/contracts/contracts/arbitrum/README.md: -------------------------------------------------------------------------------- 1 | # Arbitrum contracts 2 | 3 | These contracts have been copied from the [Arbitrum repo](https://github.com/OffchainLabs/arbitrum). 4 | 5 | They are also available as part of the npm packages [arb-bridge-eth](https://www.npmjs.com/package/arb-bridge-eth) and [arb-bridge-peripherals](https://www.npmjs.com/package/arb-bridge-peripherals). The reason for copying them rather than installing those packages is the contracts only support Solidity `^0.6.11`, so we had to change the version to `^0.7.6` for it to be compatible with our other contracts. 6 | -------------------------------------------------------------------------------- /packages/contracts/contracts/base/IMulticall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | pragma abicoder v2; 5 | 6 | /** 7 | * @title Multicall interface 8 | * @notice Enables calling multiple methods in a single call to the contract 9 | */ 10 | interface IMulticall { 11 | /** 12 | * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed 13 | * @param data The encoded function data for each of the calls to make to this contract 14 | * @return results The results from each of the calls passed in via data 15 | */ 16 | function multicall(bytes[] calldata data) external returns (bytes[] memory results); 17 | } 18 | -------------------------------------------------------------------------------- /packages/contracts/contracts/base/Multicall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | pragma abicoder v2; 5 | 6 | import "./IMulticall.sol"; 7 | 8 | // Inspired by https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol 9 | // Note: Removed payable from the multicall 10 | 11 | /** 12 | * @title Multicall 13 | * @notice Enables calling multiple methods in a single call to the contract 14 | */ 15 | abstract contract Multicall is IMulticall { 16 | /// @inheritdoc IMulticall 17 | function multicall(bytes[] calldata data) external override returns (bytes[] memory results) { 18 | results = new bytes[](data.length); 19 | for (uint256 i = 0; i < data.length; i++) { 20 | (bool success, bytes memory result) = address(this).delegatecall(data[i]); 21 | 22 | if (!success) { 23 | // Next 5 lines from https://ethereum.stackexchange.com/a/83577 24 | if (result.length < 68) revert(); 25 | assembly { 26 | result := add(result, 0x04) 27 | } 28 | revert(abi.decode(result, (string))); 29 | } 30 | 31 | results[i] = result; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/contracts/contracts/curation/IGraphCurationToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; 6 | 7 | interface IGraphCurationToken is IERC20Upgradeable { 8 | function initialize(address _owner) external; 9 | 10 | function burnFrom(address _account, uint256 _amount) external; 11 | 12 | function mint(address _to, uint256 _amount) external; 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/IServiceRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | interface IServiceRegistry { 6 | struct IndexerService { 7 | string url; 8 | string geohash; 9 | } 10 | 11 | function register(string calldata _url, string calldata _geohash) external; 12 | 13 | function registerFor(address _indexer, string calldata _url, string calldata _geohash) external; 14 | 15 | function unregister() external; 16 | 17 | function unregisterFor(address _indexer) external; 18 | 19 | function isRegistered(address _indexer) external view returns (bool); 20 | } 21 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/ISubgraphNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 6 | 7 | interface ISubgraphNFT is IERC721 { 8 | // -- Config -- 9 | 10 | function setMinter(address _minter) external; 11 | 12 | function setTokenDescriptor(address _tokenDescriptor) external; 13 | 14 | function setBaseURI(string memory _baseURI) external; 15 | 16 | // -- Actions -- 17 | 18 | function mint(address _to, uint256 _tokenId) external; 19 | 20 | function burn(uint256 _tokenId) external; 21 | 22 | function setSubgraphMetadata(uint256 _tokenId, bytes32 _subgraphMetadata) external; 23 | 24 | function tokenURI(uint256 _tokenId) external view returns (string memory); 25 | } 26 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/ISubgraphNFTDescriptor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | /// @title Describes subgraph NFT tokens via URI 6 | interface ISubgraphNFTDescriptor { 7 | /// @notice Produces the URI describing a particular token ID for a Subgraph 8 | /// @dev Note this URI may be data: URI with the JSON contents directly inlined 9 | /// @param _minter Address of the allowed minter 10 | /// @param _tokenId The ID of the subgraph NFT for which to produce a description, which may not be valid 11 | /// @param _baseURI The base URI that could be prefixed to the final URI 12 | /// @param _subgraphMetadata Subgraph metadata set for the subgraph 13 | /// @return The URI of the ERC721-compliant metadata 14 | function tokenURI( 15 | address _minter, 16 | uint256 _tokenId, 17 | string calldata _baseURI, 18 | bytes32 _subgraphMetadata 19 | ) external view returns (string memory); 20 | } 21 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/L1GNSStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | pragma abicoder v2; 5 | 6 | /** 7 | * @title L1GNSV1Storage 8 | * @notice This contract holds all the L1-specific storage variables for the L1GNS contract, version 1 9 | * @dev When adding new versions, make sure to move the gap to the new version and 10 | * reduce the size of the gap accordingly. 11 | */ 12 | abstract contract L1GNSV1Storage { 13 | /// True for subgraph IDs that have been transferred to L2 14 | mapping(uint256 => bool) public subgraphTransferredToL2; 15 | /// @dev Storage gap to keep storage slots fixed in future versions 16 | uint256[50] private __gap; 17 | } 18 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/ServiceRegistryStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../governance/Managed.sol"; 6 | 7 | import "./IServiceRegistry.sol"; 8 | 9 | contract ServiceRegistryV1Storage is Managed { 10 | // -- State -- 11 | 12 | mapping(address => IServiceRegistry.IndexerService) public services; 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/SubgraphNFTDescriptor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../libraries/Base58Encoder.sol"; 6 | import "./ISubgraphNFTDescriptor.sol"; 7 | 8 | /// @title Describes subgraph NFT tokens via URI 9 | contract SubgraphNFTDescriptor is ISubgraphNFTDescriptor { 10 | /// @inheritdoc ISubgraphNFTDescriptor 11 | function tokenURI( 12 | address /* _minter */, 13 | uint256 /* _tokenId */, 14 | string calldata _baseURI, 15 | bytes32 _subgraphMetadata 16 | ) external pure override returns (string memory) { 17 | bytes memory b58 = Base58Encoder.encode(abi.encodePacked(Base58Encoder.sha256MultiHash, _subgraphMetadata)); 18 | if (bytes(_baseURI).length == 0) { 19 | return string(b58); 20 | } 21 | return string(abi.encodePacked(_baseURI, b58)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/contracts/contracts/discovery/erc1056/IEthereumDIDRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | interface IEthereumDIDRegistry { 6 | function identityOwner(address identity) external view returns (address); 7 | 8 | function setAttribute(address identity, bytes32 name, bytes calldata value, uint256 validity) external; 9 | } 10 | -------------------------------------------------------------------------------- /packages/contracts/contracts/disputes/DisputeManagerStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../governance/Managed.sol"; 6 | 7 | import "./IDisputeManager.sol"; 8 | 9 | contract DisputeManagerV1Storage is Managed { 10 | // -- State -- 11 | 12 | bytes32 internal DOMAIN_SEPARATOR; 13 | 14 | // The arbitrator is solely in control of arbitrating disputes 15 | address public arbitrator; 16 | 17 | // Minimum deposit required to create a Dispute 18 | uint256 public minimumDeposit; 19 | 20 | // -- Slot 0xf 21 | // Percentage of indexer slashed funds to assign as a reward to fisherman in successful dispute 22 | // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%) 23 | uint32 public fishermanRewardPercentage; 24 | 25 | // Percentage of indexer stake to slash on disputes 26 | // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%) 27 | uint32 public qrySlashingPercentage; 28 | uint32 public idxSlashingPercentage; 29 | 30 | // -- Slot 0x10 31 | // Disputes created : disputeID => Dispute 32 | // disputeID - check creation functions to see how disputeID is built 33 | mapping(bytes32 => IDisputeManager.Dispute) public disputes; 34 | } 35 | -------------------------------------------------------------------------------- /packages/contracts/contracts/epochs/EpochManagerStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../governance/Managed.sol"; 6 | 7 | contract EpochManagerV1Storage is Managed { 8 | // -- State -- 9 | 10 | // Epoch length in blocks 11 | uint256 public epochLength; 12 | 13 | // Epoch that was last run 14 | uint256 public lastRunEpoch; 15 | 16 | // Block and epoch when epoch length was last updated 17 | uint256 public lastLengthUpdateEpoch; 18 | uint256 public lastLengthUpdateBlock; 19 | } 20 | -------------------------------------------------------------------------------- /packages/contracts/contracts/epochs/IEpochManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | interface IEpochManager { 6 | // -- Configuration -- 7 | 8 | function setEpochLength(uint256 _epochLength) external; 9 | 10 | // -- Epochs 11 | 12 | function runEpoch() external; 13 | 14 | // -- Getters -- 15 | 16 | function isCurrentEpochRun() external view returns (bool); 17 | 18 | function blockNum() external view returns (uint256); 19 | 20 | function blockHash(uint256 _block) external view returns (bytes32); 21 | 22 | function currentEpoch() external view returns (uint256); 23 | 24 | function currentEpochBlock() external view returns (uint256); 25 | 26 | function currentEpochBlockSinceStart() external view returns (uint256); 27 | 28 | function epochsSince(uint256 _epoch) external view returns (uint256); 29 | 30 | function epochsSinceUpdate() external view returns (uint256); 31 | } 32 | -------------------------------------------------------------------------------- /packages/contracts/contracts/gateway/ICallhookReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | /** 4 | * @title Interface for contracts that can receive callhooks through the Arbitrum GRT bridge 5 | * @dev Any contract that can receive a callhook on L2, sent through the bridge from L1, must 6 | * be allowlisted by the governor, but also implement this interface that contains 7 | * the function that will actually be called by the L2GraphTokenGateway. 8 | */ 9 | pragma solidity ^0.7.6; 10 | 11 | interface ICallhookReceiver { 12 | /** 13 | * @notice Receive tokens with a callhook from the bridge 14 | * @param _from Token sender in L1 15 | * @param _amount Amount of tokens that were transferred 16 | * @param _data ABI-encoded callhook data 17 | */ 18 | function onTokenTransfer(address _from, uint256 _amount, bytes calldata _data) external; 19 | } 20 | -------------------------------------------------------------------------------- /packages/contracts/contracts/governance/IController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity >=0.6.12 <0.8.0; 4 | 5 | interface IController { 6 | function getGovernor() external view returns (address); 7 | 8 | // -- Registry -- 9 | 10 | function setContractProxy(bytes32 _id, address _contractAddress) external; 11 | 12 | function unsetContractProxy(bytes32 _id) external; 13 | 14 | function updateController(bytes32 _id, address _controller) external; 15 | 16 | function getContractProxy(bytes32 _id) external view returns (address); 17 | 18 | // -- Pausing -- 19 | 20 | function setPartialPaused(bool _partialPaused) external; 21 | 22 | function setPaused(bool _paused) external; 23 | 24 | function setPauseGuardian(address _newPauseGuardian) external; 25 | 26 | function paused() external view returns (bool); 27 | 28 | function partialPaused() external view returns (bool); 29 | } 30 | -------------------------------------------------------------------------------- /packages/contracts/contracts/governance/IManaged.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import { IController } from "./IController.sol"; 6 | 7 | /** 8 | * @title Managed Interface 9 | * @dev Interface for contracts that can be managed by a controller. 10 | */ 11 | interface IManaged { 12 | /** 13 | * @notice Set the controller that manages this contract 14 | * @dev Only the current controller can set a new controller 15 | * @param _controller Address of the new controller 16 | */ 17 | function setController(address _controller) external; 18 | 19 | /** 20 | * @notice Sync protocol contract addresses from the Controller registry 21 | * @dev This function will cache all the contracts using the latest addresses. 22 | * Anyone can call the function whenever a Proxy contract change in the 23 | * controller to ensure the protocol is using the latest version. 24 | */ 25 | function syncAllContracts() external; 26 | 27 | /** 28 | * @notice Get the Controller that manages this contract 29 | * @return The Controller as an IController interface 30 | */ 31 | function controller() external view returns (IController); 32 | } 33 | -------------------------------------------------------------------------------- /packages/contracts/contracts/l2/discovery/L2GNSStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | pragma abicoder v2; 5 | 6 | import { IL2GNS } from "./IL2GNS.sol"; 7 | 8 | /** 9 | * @title L2GNSV1Storage 10 | * @notice This contract holds all the L2-specific storage variables for the L2GNS contract, version 1 11 | * @dev 12 | */ 13 | abstract contract L2GNSV1Storage { 14 | /// Data for subgraph transfer from L1 to L2 15 | mapping(uint256 => IL2GNS.SubgraphL2TransferData) public subgraphL2TransferData; 16 | /// @dev Storage gap to keep storage slots fixed in future versions 17 | uint256[50] private __gap; 18 | } 19 | -------------------------------------------------------------------------------- /packages/contracts/contracts/l2/staking/IL2Staking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity >=0.6.12 <0.8.0; 4 | pragma abicoder v2; 5 | 6 | import { IStaking } from "../../staking/IStaking.sol"; 7 | import { IL2StakingBase } from "./IL2StakingBase.sol"; 8 | 9 | /** 10 | * @title Interface for the L2 Staking contract 11 | * @notice This is the interface that should be used when interacting with the L2 Staking contract. 12 | * It extends the IStaking interface with the functions that are specific to L2, adding the callhook receiver 13 | * to receive transferred stake and delegation from L1. 14 | * @dev Note that L2Staking doesn't actually inherit this interface. This is because of 15 | * the custom setup of the Staking contract where part of the functionality is implemented 16 | * in a separate contract (StakingExtension) to which calls are delegated through the fallback function. 17 | */ 18 | interface IL2Staking is IStaking, IL2StakingBase { 19 | /// @dev Message codes for the L1 -> L2 bridge callhook 20 | enum L1MessageCodes { 21 | RECEIVE_INDEXER_STAKE_CODE, 22 | RECEIVE_DELEGATION_CODE 23 | } 24 | 25 | /// @dev Encoded message struct when receiving indexer stake through the bridge 26 | struct ReceiveIndexerStakeData { 27 | address indexer; 28 | } 29 | 30 | /// @dev Encoded message struct when receiving delegation through the bridge 31 | struct ReceiveDelegationData { 32 | address indexer; 33 | address delegator; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/contracts/contracts/l2/staking/IL2StakingBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import { ICallhookReceiver } from "../../gateway/ICallhookReceiver.sol"; 6 | 7 | /** 8 | * @title Base interface for the L2Staking contract. 9 | * @notice This interface is used to define the callhook receiver interface that is implemented by L2Staking. 10 | * @dev Note it includes only the L2-specific functionality, not the full IStaking interface. 11 | */ 12 | interface IL2StakingBase is ICallhookReceiver { 13 | event TransferredDelegationReturnedToDelegator(address indexed indexer, address indexed delegator, uint256 amount); 14 | } 15 | -------------------------------------------------------------------------------- /packages/contracts/contracts/libraries/HexStrings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | /// @title HexStrings 6 | /// Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/8dd744fc1843d285c38e54e9d439dea7f6b93495/contracts/utils/Strings.sol 7 | library HexStrings { 8 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 9 | 10 | /// @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 11 | function toString(uint256 value) internal pure returns (string memory) { 12 | if (value == 0) { 13 | return "0x00"; 14 | } 15 | uint256 temp = value; 16 | uint256 length = 0; 17 | while (temp != 0) { 18 | length++; 19 | temp >>= 8; 20 | } 21 | return toHexString(value, length); 22 | } 23 | 24 | /// @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 25 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 26 | bytes memory buffer = new bytes(2 * length + 2); 27 | buffer[0] = "0"; 28 | buffer[1] = "x"; 29 | for (uint256 i = 2 * length + 1; i > 1; --i) { 30 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 31 | value >>= 4; 32 | } 33 | require(value == 0, "Strings: hex length insufficient"); 34 | return string(buffer); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/contracts/contracts/rewards/RewardsManagerStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "./IRewardsManager.sol"; 6 | import "../governance/Managed.sol"; 7 | 8 | contract RewardsManagerV1Storage is Managed { 9 | // -- State -- 10 | 11 | uint256 private __DEPRECATED_issuanceRate; // solhint-disable-line var-name-mixedcase 12 | uint256 public accRewardsPerSignal; 13 | uint256 public accRewardsPerSignalLastBlockUpdated; 14 | 15 | // Address of role allowed to deny rewards on subgraphs 16 | address public subgraphAvailabilityOracle; 17 | 18 | // Subgraph related rewards: subgraph deployment ID => subgraph rewards 19 | mapping(bytes32 => IRewardsManager.Subgraph) public subgraphs; 20 | 21 | // Subgraph denylist : subgraph deployment ID => block when added or zero (if not denied) 22 | mapping(bytes32 => uint256) public denylist; 23 | } 24 | 25 | contract RewardsManagerV2Storage is RewardsManagerV1Storage { 26 | // Minimum amount of signaled tokens on a subgraph required to accrue rewards 27 | uint256 public minimumSubgraphSignal; 28 | } 29 | 30 | contract RewardsManagerV3Storage is RewardsManagerV2Storage { 31 | // Snapshot of the total supply of GRT when accRewardsPerSignal was last updated 32 | uint256 private __DEPRECATED_tokenSupplySnapshot; // solhint-disable-line var-name-mixedcase 33 | } 34 | 35 | contract RewardsManagerV4Storage is RewardsManagerV3Storage { 36 | // GRT issued for indexer rewards per block 37 | uint256 public issuancePerBlock; 38 | } 39 | -------------------------------------------------------------------------------- /packages/contracts/contracts/staking/IL1Staking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity >=0.6.12 <0.8.0; 4 | pragma abicoder v2; 5 | 6 | import { IStaking } from "./IStaking.sol"; 7 | import { IL1StakingBase } from "./IL1StakingBase.sol"; 8 | 9 | /** 10 | * @title Interface for the L1 Staking contract 11 | * @notice This is the interface that should be used when interacting with the L1 Staking contract. 12 | * It extends the IStaking interface with the functions that are specific to L1, adding the transfer tools 13 | * to send stake and delegation to L2. 14 | * @dev Note that L1Staking doesn't actually inherit this interface. This is because of 15 | * the custom setup of the Staking contract where part of the functionality is implemented 16 | * in a separate contract (StakingExtension) to which calls are delegated through the fallback function. 17 | */ 18 | interface IL1Staking is IStaking, IL1StakingBase { 19 | // Nothing to see here 20 | } 21 | -------------------------------------------------------------------------------- /packages/contracts/contracts/staking/IStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity >=0.6.12 <0.8.0; 4 | pragma abicoder v2; 5 | 6 | import { IStakingBase } from "./IStakingBase.sol"; 7 | import { IStakingExtension } from "./IStakingExtension.sol"; 8 | import { IMulticall } from "../base/IMulticall.sol"; 9 | import { IManaged } from "../governance/IManaged.sol"; 10 | 11 | /** 12 | * @title Interface for the Staking contract 13 | * @notice This is the interface that should be used when interacting with the Staking contract. 14 | * @dev Note that Staking doesn't actually inherit this interface. This is because of 15 | * the custom setup of the Staking contract where part of the functionality is implemented 16 | * in a separate contract (StakingExtension) to which calls are delegated through the fallback function. 17 | */ 18 | interface IStaking is IStakingBase, IStakingExtension, IMulticall, IManaged { 19 | // Nothing to see here 20 | } 21 | -------------------------------------------------------------------------------- /packages/contracts/contracts/staking/L1StakingStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | pragma abicoder v2; 5 | 6 | import { IL1GraphTokenLockTransferTool } from "./IL1GraphTokenLockTransferTool.sol"; 7 | 8 | /** 9 | * @title L1StakingV1Storage 10 | * @notice This contract holds all the L1-specific storage variables for the L1Staking contract, version 1 11 | * @dev When adding new versions, make sure to move the gap to the new version and 12 | * reduce the size of the gap accordingly. 13 | */ 14 | abstract contract L1StakingV1Storage { 15 | /// If an indexer has transferred to L2, this mapping will hold the indexer's address in L2 16 | mapping(address => address) public indexerTransferredToL2; 17 | /// @dev For locked indexers/delegations, this contract holds the mapping of L1 to L2 addresses 18 | IL1GraphTokenLockTransferTool internal l1GraphTokenLockTransferTool; 19 | /// @dev Storage gap to keep storage slots fixed in future versions 20 | uint256[50] private __gap; 21 | } 22 | -------------------------------------------------------------------------------- /packages/contracts/contracts/staking/libs/MathUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "@openzeppelin/contracts/math/SafeMath.sol"; 6 | 7 | /** 8 | * @title MathUtils Library 9 | * @notice A collection of functions to perform math operations 10 | */ 11 | library MathUtils { 12 | using SafeMath for uint256; 13 | 14 | /** 15 | * @dev Calculates the weighted average of two values pondering each of these 16 | * values based on configured weights. The contribution of each value N is 17 | * weightN/(weightA + weightB). The calculation rounds up to ensure the result 18 | * is always greater than the smallest of the two values. 19 | * @param valueA The amount for value A 20 | * @param weightA The weight to use for value A 21 | * @param valueB The amount for value B 22 | * @param weightB The weight to use for value B 23 | */ 24 | function weightedAverageRoundingUp( 25 | uint256 valueA, 26 | uint256 weightA, 27 | uint256 valueB, 28 | uint256 weightB 29 | ) internal pure returns (uint256) { 30 | return valueA.mul(weightA).add(valueB.mul(weightB)).add(weightA.add(weightB).sub(1)).div(weightA.add(weightB)); 31 | } 32 | 33 | /** 34 | * @dev Returns the minimum of two numbers. 35 | */ 36 | function min(uint256 x, uint256 y) internal pure returns (uint256) { 37 | return x <= y ? x : y; 38 | } 39 | 40 | /** 41 | * @dev Returns the difference between two numbers or zero if negative. 42 | */ 43 | function diffOrZero(uint256 x, uint256 y) internal pure returns (uint256) { 44 | return (x > y) ? x.sub(y) : 0; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/CallhookReceiverMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../gateway/ICallhookReceiver.sol"; 6 | 7 | /** 8 | * @title GovernedMock contract 9 | */ 10 | contract CallhookReceiverMock is ICallhookReceiver { 11 | event TransferReceived(address from, uint256 amount, uint256 foo, uint256 bar); 12 | 13 | /** 14 | * @dev Receive tokens with a callhook from the bridge 15 | * Expects two uint256 values encoded in _data. 16 | * Reverts if the first of these values is zero. 17 | * @param _from Token sender in L1 18 | * @param _amount Amount of tokens that were transferred 19 | * @param _data ABI-encoded callhook data 20 | */ 21 | function onTokenTransfer(address _from, uint256 _amount, bytes calldata _data) external override { 22 | uint256 foo; 23 | uint256 bar; 24 | (foo, bar) = abi.decode(_data, (uint256, uint256)); 25 | require(foo != 0, "FOO_IS_ZERO"); 26 | emit TransferReceived(_from, _amount, foo, bar); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/GovernedMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../governance/Governed.sol"; 6 | 7 | /** 8 | * @title GovernedMock contract 9 | */ 10 | contract GovernedMock is Governed { 11 | constructor() { 12 | Governed._initialize(msg.sender); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/L1GraphTokenLockTransferToolBadMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.6; 4 | pragma experimental ABIEncoderV2; 5 | 6 | contract L1GraphTokenLockTransferToolBadMock { 7 | mapping(address => address) public l2WalletAddress; 8 | 9 | function setL2WalletAddress(address _l1Address, address _l2Address) external { 10 | l2WalletAddress[_l1Address] = _l2Address; 11 | } 12 | 13 | // Sends 1 wei less than requested 14 | function pullETH(address _l1Wallet, uint256 _amount) external { 15 | require(l2WalletAddress[_l1Wallet] != address(0), "L1GraphTokenLockTransferToolMock: unknown L1 wallet"); 16 | (bool success, ) = payable(msg.sender).call{ value: _amount - 1 }(""); 17 | require(success, "L1GraphTokenLockTransferToolMock: ETH pull failed"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/L1GraphTokenLockTransferToolMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.6; 4 | pragma experimental ABIEncoderV2; 5 | 6 | contract L1GraphTokenLockTransferToolMock { 7 | mapping(address => address) public l2WalletAddress; 8 | 9 | function setL2WalletAddress(address _l1Address, address _l2Address) external { 10 | l2WalletAddress[_l1Address] = _l2Address; 11 | } 12 | 13 | function pullETH(address _l1Wallet, uint256 _amount) external { 14 | require(l2WalletAddress[_l1Wallet] != address(0), "L1GraphTokenLockTransferToolMock: unknown L1 wallet"); 15 | (bool success, ) = payable(msg.sender).call{ value: _amount }(""); 16 | require(success, "L1GraphTokenLockTransferToolMock: ETH pull failed"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/arbitrum/ArbSysMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | /** 6 | * @title ArbSys Mock Contract 7 | * @dev This is a mock implementation of the ArbSys precompiled contract used in Arbitrum 8 | * It's used for testing the L2GraphTokenGateway contract 9 | */ 10 | contract ArbSysMock { 11 | event L2ToL1Tx(address indexed from, address indexed to, uint256 indexed id, bytes data); 12 | 13 | /** 14 | * @notice Send a transaction to L1 15 | * @param destination The address on L1 to send the transaction to 16 | * @param calldataForL1 The calldata for the transaction 17 | * @return A unique identifier for this L2-to-L1 transaction 18 | */ 19 | function sendTxToL1(address destination, bytes calldata calldataForL1) external returns (uint256) { 20 | uint256 id = 1; // Always return 1 for testing 21 | emit L2ToL1Tx(msg.sender, destination, id, calldataForL1); 22 | return id; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/ens/IENS.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.6; 2 | 3 | // Needed for abi and typechain in the npm package 4 | interface IENS { 5 | function owner(bytes32 node) external view returns (address); 6 | 7 | // Must call setRecord, not setOwner, We must namehash it ourselves as well 8 | function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external; 9 | } 10 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/ens/IPublicResolver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.6; 2 | 3 | // Needed for abi and typechain in the npm package 4 | interface IPublicResolver { 5 | function text(bytes32 node, string calldata key) external view returns (string memory); 6 | 7 | function setText(bytes32 node, string calldata key, string calldata value) external; 8 | } 9 | -------------------------------------------------------------------------------- /packages/contracts/contracts/tests/ens/ITestRegistrar.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.6; 2 | 3 | interface ITestRegistrar { 4 | function register(bytes32 label, address owner) external; 5 | } 6 | -------------------------------------------------------------------------------- /packages/contracts/contracts/token/IGraphToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | interface IGraphToken is IERC20 { 8 | // -- Mint and Burn -- 9 | 10 | function burn(uint256 amount) external; 11 | 12 | function burnFrom(address _from, uint256 amount) external; 13 | 14 | function mint(address _to, uint256 _amount) external; 15 | 16 | // -- Mint Admin -- 17 | 18 | function addMinter(address _account) external; 19 | 20 | function removeMinter(address _account) external; 21 | 22 | function renounceMinter() external; 23 | 24 | function isMinter(address _account) external view returns (bool); 25 | 26 | // -- Permit -- 27 | 28 | function permit( 29 | address _owner, 30 | address _spender, 31 | uint256 _value, 32 | uint256 _deadline, 33 | uint8 _v, 34 | bytes32 _r, 35 | bytes32 _s 36 | ) external; 37 | 38 | // -- Allowance -- 39 | 40 | function increaseAllowance(address spender, uint256 addedValue) external returns (bool); 41 | 42 | function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); 43 | } 44 | -------------------------------------------------------------------------------- /packages/contracts/contracts/upgrades/IGraphProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | interface IGraphProxy { 6 | function admin() external returns (address); 7 | 8 | function setAdmin(address _newAdmin) external; 9 | 10 | function implementation() external returns (address); 11 | 12 | function pendingImplementation() external returns (address); 13 | 14 | function upgradeTo(address _newImplementation) external; 15 | 16 | function acceptUpgrade() external; 17 | 18 | function acceptUpgradeAndCall(bytes calldata data) external; 19 | } 20 | -------------------------------------------------------------------------------- /packages/contracts/contracts/utils/TokenUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.7.6; 4 | 5 | import "../token/IGraphToken.sol"; 6 | 7 | library TokenUtils { 8 | /** 9 | * @dev Pull tokens from an address to this contract. 10 | * @param _graphToken Token to transfer 11 | * @param _from Address sending the tokens 12 | * @param _amount Amount of tokens to transfer 13 | */ 14 | function pullTokens(IGraphToken _graphToken, address _from, uint256 _amount) internal { 15 | if (_amount > 0) { 16 | require(_graphToken.transferFrom(_from, address(this), _amount), "!transfer"); 17 | } 18 | } 19 | 20 | /** 21 | * @dev Push tokens from this contract to a receiving address. 22 | * @param _graphToken Token to transfer 23 | * @param _to Address receiving the tokens 24 | * @param _amount Amount of tokens to transfer 25 | */ 26 | function pushTokens(IGraphToken _graphToken, address _to, uint256 _amount) internal { 27 | if (_amount > 0) { 28 | require(_graphToken.transfer(_to, _amount), "!transfer"); 29 | } 30 | } 31 | 32 | /** 33 | * @dev Burn tokens held by this contract. 34 | * @param _graphToken Token to burn 35 | * @param _amount Amount of tokens to burn 36 | */ 37 | function burnTokens(IGraphToken _graphToken, uint256 _amount) internal { 38 | if (_amount > 0) { 39 | _graphToken.burn(_amount); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/contracts/index.d.ts: -------------------------------------------------------------------------------- 1 | // Export all TypeChain generated types 2 | export * from './typechain-types' 3 | 4 | // Keep the original IPFS declaration 5 | declare module 'ipfs-http-client' 6 | -------------------------------------------------------------------------------- /packages/contracts/prettier.config.cjs: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../prettier.config.cjs') 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | } 6 | -------------------------------------------------------------------------------- /packages/contracts/scripts/analyze: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Before running: 4 | # This tool requires to have solc installed. 5 | # Ensure that you have the binaries installed by pip3 in your path. 6 | # Install: 7 | # - https://github.com/crytic/slither#how-to-install 8 | # Usage: 9 | # - https://github.com/crytic/slither/wiki/Usage 10 | 11 | mkdir -p reports 12 | 13 | pip3 install --user slither-analyzer && \ 14 | yarn build && \ 15 | 16 | echo "Analyzing contracts..." 17 | slither . \ 18 | --hardhat-ignore-compile \ 19 | --hardhat-artifacts-directory ./artifacts \ 20 | --sarif - \ 21 | --filter-paths "contracts/bancor/.*|contracts/tests/.*|contracts/staking/libs/Exponential.*|contracts/staking/libs/LibFixedMath.*|contracts/staking/libs/MathUtils.*" \ 22 | --exclude-dependencies \ 23 | --exclude similar-names,naming-convention \ 24 | --disable-color \ 25 | &> reports/analyzer-report.sarif && \ 26 | echo "Slither report generated at ./reports/analyzer-report.sarif" 27 | echo "Checking ERC compliance..." 28 | slither-check-erc build/flatten/GraphToken.sol GraphToken &> reports/analyzer-report-erc.log 29 | echo "Compliance report generated at ./reports/analyzer-report-erc.log" 30 | 31 | echo "Done!" 32 | -------------------------------------------------------------------------------- /packages/contracts/scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | # Build 6 | yarn compile 7 | -------------------------------------------------------------------------------- /packages/contracts/scripts/clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUT_DIR="build/flatten" 4 | 5 | mkdir -p ${OUT_DIR} 6 | 7 | echo "Cleaning flattened contracts..." 8 | 9 | FLATTENED_FILES=( 10 | "$OUT_DIR/Controller.sol" 11 | "$OUT_DIR/GNS.sol" 12 | "$OUT_DIR/ServiceRegistry.sol" 13 | "$OUT_DIR/Curation.sol" 14 | "$OUT_DIR/GraphCurationToken.sol" 15 | "$OUT_DIR/Staking.sol" 16 | "$OUT_DIR/RewardsManager.sol" 17 | "$OUT_DIR/GraphToken.sol" 18 | "$OUT_DIR/EpochManager.sol" 19 | "$OUT_DIR/GraphProxy.sol" 20 | ) 21 | 22 | for path in ${FLATTENED_FILES[@]}; do 23 | echo "Clean > ${path}" 24 | sed -i \ 25 | -e "s|pragma solidity.*||g" \ 26 | -e "s|// SPDX-License-Identifier:.*||g" \ 27 | -e 's|pragma abicoder v2;|//pragma abicoder v2;|g' \ 28 | -e '1s|^|pragma abicoder v2;\n|' $path 29 | done 30 | -------------------------------------------------------------------------------- /packages/contracts/scripts/coverage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | yarn build 6 | 7 | echo {} > addresses-local.json 8 | 9 | DISABLE_SECURE_ACCOUNTS=true \ 10 | L1_GRAPH_CONFIG=config/graph.hardhat.yml \ 11 | L2_GRAPH_CONFIG=config/graph.arbitrum-hardhat.yml \ 12 | ADDRESS_BOOK=addresses-local.json \ 13 | npx hardhat coverage $@ 14 | -------------------------------------------------------------------------------- /packages/contracts/scripts/flatten: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUT_DIR="build/flatten" 4 | 5 | mkdir -p ${OUT_DIR} 6 | 7 | echo "Flattening contracts..." 8 | 9 | FILES=( 10 | "contracts/governance/Controller.sol" 11 | "contracts/discovery/GNS.sol" 12 | "contracts/discovery/ServiceRegistry.sol" 13 | "contracts/curation/Curation.sol" 14 | "contracts/curation/GraphCurationToken.sol" 15 | "contracts/staking/Staking.sol" 16 | "contracts/rewards/RewardsManager.sol" 17 | "contracts/token/GraphToken.sol" 18 | "contracts/epochs/EpochManager.sol" 19 | "contracts/upgrades/GraphProxy.sol" 20 | ) 21 | 22 | for path in ${FILES[@]}; do 23 | IFS='/' 24 | parts=( $path ) 25 | name=${parts[${#parts[@]}-1]} 26 | echo "Flatten > ${name}" 27 | hardhat flatten "${path}" > "${OUT_DIR}/${name}" 28 | done 29 | 30 | echo "Done!" 31 | -------------------------------------------------------------------------------- /packages/contracts/scripts/myth: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Before running: 4 | # This tool requires to have solc installed. 5 | # Ensure that you have the binaries installed by pip3 in your path. 6 | # Install: 7 | # - https://github.com/ConsenSys/mythril#installation-and-setup 8 | # Usage: 9 | # - https://github.com/ConsenSys/mythril#usage 10 | 11 | pip3 install --user mythril && \ 12 | yarn build && \ 13 | mkdir -p reports/myth 14 | 15 | echo "Myth Analysis..." 16 | 17 | start_time="$(date -u +%s)" 18 | 19 | for filename in build/flatten/*.sol; do 20 | step_start_time="$(date -u +%s)" 21 | echo "Scanning $filename ..." 22 | myth analyze \ 23 | --parallel-solving \ 24 | --execution-timeout 30 \ 25 | --solver-timeout 6000 \ 26 | -o markdown "$filename" \ 27 | &> "reports/myth/$(basename "$filename" .sol)-report.md" && \ 28 | 29 | end_time="$(date -u +%s)" 30 | total_elapsed="$(($end_time-$start_time))" 31 | step_elapsed="$(($end_time-$step_start_time))" 32 | echo "> Took $step_elapsed seconds. Total elapsed: $total_elapsed seconds." 33 | done 34 | 35 | echo "Done!" -------------------------------------------------------------------------------- /packages/contracts/scripts/ops/parseTestnetAddresses.ts: -------------------------------------------------------------------------------- 1 | #!ts-node 2 | 3 | // Accepts a CSV file: field1 name, field2 Ethereum address 4 | // Validates the address is valid, trims and exit on error 5 | // Outputs a json in the format used by the distribution script 6 | 7 | import fs from 'fs' 8 | import { utils } from 'ethers' 9 | 10 | const { getAddress } = utils 11 | 12 | interface TeamMember { 13 | name: string 14 | address: string 15 | } 16 | 17 | export const teamAddresses: Array = [] 18 | 19 | function main() { 20 | const data = fs.readFileSync('indexers.csv', 'utf8') 21 | const entries = data.split('\n').map(e => e.trim()) 22 | for (const entry of entries) { 23 | if (!entry) continue 24 | 25 | const [name, address] = entry.split(',').map(e => e.trim()) 26 | 27 | // Verify address 28 | try { 29 | getAddress(address.trim()) 30 | } catch (_) { 31 | console.log('Invalid', name, address) 32 | process.exit(1) 33 | } 34 | 35 | // Add to member list 36 | const member = { 37 | name, 38 | address, 39 | } 40 | teamAddresses.push(member) 41 | } 42 | 43 | // Out 44 | console.log(JSON.stringify(teamAddresses)) 45 | } 46 | 47 | main() 48 | -------------------------------------------------------------------------------- /packages/contracts/scripts/ops/testDisputeConflict/acceptDispute.ts: -------------------------------------------------------------------------------- 1 | import { Wallet } from 'ethers' 2 | import hre from 'hardhat' 3 | 4 | async function main() { 5 | const graph = hre.graph() 6 | const arbitratorPrivateKey = process.env.ARBITRATOR_PRIVATE_KEY 7 | const arbitrator = new Wallet(arbitratorPrivateKey, graph.provider) 8 | console.log('Arbitrator:', arbitrator.address) 9 | 10 | const disputeId = '0x35e6e68aa71ee59cb710d8005563d63d644f11f2eee879eca9bc22f523c9fade' 11 | console.log('Dispute ID:', disputeId) 12 | 13 | // Accept dispute 14 | await graph.contracts.DisputeManager.connect(arbitrator).acceptDispute(disputeId) 15 | } 16 | 17 | main().catch((error) => { 18 | console.error(error) 19 | process.exitCode = 1 20 | }) 21 | -------------------------------------------------------------------------------- /packages/contracts/scripts/predeploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat addresses.json | 4 | jq '."1"."IENS".address = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"' | 5 | jq '."5"."IENS".address = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"' | 6 | jq '."1"."IEthereumDIDRegistry".address = "0xdCa7EF03e98e0DC2B855bE647C39ABe984fcF21B"' | 7 | jq '."5"."IEthereumDIDRegistry".address = "0xdCa7EF03e98e0DC2B855bE647C39ABe984fcF21B"' | 8 | jq '."42161"."IEthereumDIDRegistry".address = "0xa9AEb1c6f14f4244547B9a0946C485DA99047638"' | 9 | jq '."421613"."IEthereumDIDRegistry".address = "0x8FFfcD6a85D29E9C33517aaf60b16FE4548f517E"' > addresses.json.tmp 10 | mv addresses.json.tmp addresses.json 11 | -------------------------------------------------------------------------------- /packages/contracts/scripts/prepack: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TYPECHAIN_DIR=dist/types 4 | 5 | set -eo pipefail 6 | set +o noglob 7 | 8 | # Build contracts 9 | yarn build 10 | 11 | # Populate distribution folder 12 | mkdir -p ${TYPECHAIN_DIR} 13 | cp -R build/abis/ dist/abis 14 | cp -R build/types/ ${TYPECHAIN_DIR} 15 | 16 | # Build and create TS declarations 17 | pushd ${TYPECHAIN_DIR} 18 | ls **/*.ts | xargs tsc --esModuleInterop 19 | popd 20 | -------------------------------------------------------------------------------- /packages/contracts/scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | source $(pwd)/scripts/evm 5 | 6 | ### Setup EVM 7 | 8 | # Ensure we compiled sources 9 | 10 | yarn build 11 | 12 | ### Cleanup 13 | function cleanup() { 14 | if [ "$RUN_EVM" = true ]; then 15 | evm_kill 16 | fi 17 | } 18 | trap cleanup EXIT 19 | 20 | # Gas reporter needs to run in its own evm instance 21 | if [ "$RUN_EVM" = true ]; then 22 | evm_kill 23 | evm_start 24 | sleep 5 25 | fi 26 | 27 | ### Main 28 | 29 | # Init address book 30 | echo {} > addresses-local.json 31 | 32 | mkdir -p reports 33 | 34 | # Run using the standalone evm instance 35 | DISABLE_SECURE_ACCOUNTS=true \ 36 | L1_GRAPH_CONFIG=config/graph.hardhat.yml \ 37 | L2_GRAPH_CONFIG=config/graph.arbitrum-hardhat.yml \ 38 | ADDRESS_BOOK=addresses-local.json \ 39 | npx hardhat test --network hardhat $@ 40 | 41 | if [ "$REPORT_GAS" = true ]; then 42 | cat reports/gas-report.log 43 | echo "" # Gas report doesn't have a newline at the end 44 | fi 45 | -------------------------------------------------------------------------------- /packages/contracts/scripts/test-coverage-file: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | # Check if a test file was provided 6 | if [ $# -eq 0 ]; then 7 | echo "Error: You must provide a test file path" 8 | echo "Usage: ./scripts/test-coverage-file test/unit/rewards/rewards.test.ts" 9 | exit 1 10 | fi 11 | 12 | # Build contracts first to ensure tests run against latest code 13 | echo "Building contracts before running coverage..." 14 | yarn build 15 | 16 | echo "Running coverage for test file: $1" 17 | DISABLE_SECURE_ACCOUNTS=true \ 18 | L1_GRAPH_CONFIG=config/graph.hardhat.yml \ 19 | L2_GRAPH_CONFIG=config/graph.arbitrum-hardhat.yml \ 20 | ADDRESS_BOOK=addresses-local.json \ 21 | npx hardhat coverage --testfiles "$1" 22 | -------------------------------------------------------------------------------- /packages/contracts/slither.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "hardhat_artifacts_directory": "./artifacts", 3 | "filter_paths": "contracts/bancor/.*|contracts/tests/.*|contracts/staking/libs/Exponential.*|contracts/staking/libs/LibFixedMath.*|contracts/staking/libs/MathUtils.*", 4 | "detectors_to_exclude": "similar-names,naming-convention", 5 | "exclude_dependencies": true 6 | } 7 | -------------------------------------------------------------------------------- /packages/contracts/tasks/contract/deploy.ts: -------------------------------------------------------------------------------- 1 | import { confirm, deploy, DeployType } from '@graphprotocol/sdk' 2 | import { greTask } from '@graphprotocol/sdk/gre' 3 | 4 | greTask('contract:deploy', 'Deploy a contract') 5 | .addPositionalParam('contract', 'Name of the contract to deploy') 6 | .addOptionalPositionalParam( 7 | 'init', 8 | 'Initialization arguments for the contract constructor. Provide arguments as comma-separated values', 9 | ) 10 | .addParam('deployType', 'Choose deploy, deploy-save, deploy-with-proxy, deploy-with-proxy-save') 11 | .addFlag('skipConfirmation', 'Skip confirmation prompt on write actions') 12 | .addFlag('buildAcceptTx', '...') 13 | .setAction(async (taskArgs, hre) => { 14 | const graph = hre.graph(taskArgs) 15 | const deployer = await graph.getDeployer() 16 | 17 | if (!Object.values(DeployType).includes(taskArgs.deployType)) { 18 | throw new Error(`Deploy type ${taskArgs.deployType} not supported`) 19 | } 20 | 21 | console.log(`Deploying ${taskArgs.contract}...`) 22 | console.log(`Init: ${taskArgs.init}`) 23 | console.log(`Deploy type: ${taskArgs.deployType}`) 24 | console.log(`Deployer: ${deployer.address}`) 25 | console.log(`Chain ID: ${graph.chainId}`) 26 | 27 | const sure = await confirm( 28 | `Are you sure to deploy ${taskArgs.contract}?`, 29 | taskArgs.skipConfirmation, 30 | ) 31 | if (!sure) return 32 | 33 | const deployment = await deploy( 34 | taskArgs.deployType, 35 | deployer, 36 | { 37 | name: taskArgs.contract, 38 | args: taskArgs.init?.split(',') || [], 39 | }, 40 | graph.addressBook, 41 | ) 42 | console.log(`Contract deployed at ${deployment.contract.address}`) 43 | }) 44 | -------------------------------------------------------------------------------- /packages/contracts/tasks/contract/upgrade.ts: -------------------------------------------------------------------------------- 1 | import { greTask } from '@graphprotocol/sdk/gre' 2 | import { deploy, DeployType, GraphNetworkAddressBook } from '@graphprotocol/sdk' 3 | 4 | greTask('contract:upgrade', 'Upgrades a contract') 5 | .addParam('contract', 'Name of the contract to upgrade') 6 | .addOptionalVariadicPositionalParam( 7 | 'init', 8 | 'Initialization arguments for the contract constructor', 9 | ) 10 | .setAction(async (taskArgs, hre) => { 11 | const graph = hre.graph(taskArgs) 12 | 13 | const { GraphProxyAdmin } = graph.contracts 14 | const { governor } = await graph.getNamedAccounts() 15 | const deployer = await graph.getDeployer() 16 | 17 | const contract = graph.contracts[taskArgs.contract] 18 | if (!contract) { 19 | throw new Error(`Contract ${taskArgs.contract} not found in address book`) 20 | } 21 | console.log(`Upgrading ${taskArgs.contract}...`) 22 | 23 | // Deploy new implementation 24 | const { contract: implementation } = await deploy( 25 | DeployType.DeployImplementationAndSave, 26 | deployer, 27 | { 28 | name: taskArgs.contract, 29 | args: taskArgs.init || [], 30 | }, 31 | new GraphNetworkAddressBook(taskArgs.addressBook, graph.chainId), 32 | ) 33 | console.log(`New implementation deployed at ${implementation.address}`) 34 | 35 | // Upgrade proxy and accept implementation 36 | await GraphProxyAdmin.connect(governor).upgrade(contract.address, implementation.address) 37 | await GraphProxyAdmin.connect(governor).acceptProxy(implementation.address, contract.address) 38 | console.log(`Proxy upgraded to ${implementation.address}`) 39 | }) 40 | -------------------------------------------------------------------------------- /packages/contracts/tasks/migrate/bridge.ts: -------------------------------------------------------------------------------- 1 | import { greTask } from '@graphprotocol/sdk/gre' 2 | import { configureL1Bridge, configureL2Bridge, setPausedBridge } from '@graphprotocol/sdk' 3 | 4 | greTask('migrate:bridge', 'Configure and unpause bridge') 5 | .addOptionalParam( 6 | 'arbitrumAddressBook', 7 | 'The path to the address book file for Arbitrum deployments', 8 | './arbitrum-addresses.json', 9 | ) 10 | .setAction(async (taskArgs, hre) => { 11 | const graph = hre.graph(taskArgs) 12 | const { governor: l1Governor } = await graph.l1.getNamedAccounts() 13 | const { governor: l2Governor } = await graph.l2.getNamedAccounts() 14 | 15 | await configureL1Bridge(graph.l1.contracts, l1Governor, { 16 | l2GRTAddress: graph.l2.contracts.GraphToken.address, 17 | l2GRTGatewayAddress: graph.l2.contracts.L2GraphTokenGateway.address, 18 | l2GNSAddress: graph.l2.contracts.L2GNS.address, 19 | l2StakingAddress: graph.l2.contracts.L2Staking.address, 20 | arbAddressBookPath: taskArgs.arbitrumAddressBook, 21 | chainId: graph.l1.chainId, 22 | }) 23 | 24 | await configureL2Bridge(graph.l2.contracts, l2Governor, { 25 | l1GRTAddress: graph.l1.contracts.GraphToken.address, 26 | l1GRTGatewayAddress: graph.l1.contracts.L1GraphTokenGateway.address, 27 | l1GNSAddress: graph.l1.contracts.L1GNS.address, 28 | l1StakingAddress: graph.l1.contracts.L1Staking.address, 29 | arbAddressBookPath: taskArgs.arbitrumAddressBook, 30 | chainId: graph.l2.chainId, 31 | }) 32 | 33 | await setPausedBridge(graph.l1.contracts, l1Governor, { paused: false }) 34 | await setPausedBridge(graph.l2.contracts, l2Governor, { paused: false }) 35 | 36 | console.log('Done!') 37 | }) 38 | -------------------------------------------------------------------------------- /packages/contracts/tasks/migrate/protocol.ts: -------------------------------------------------------------------------------- 1 | import { deployGraphNetwork, GraphChainId } from '@graphprotocol/sdk' 2 | import { greTask } from '@graphprotocol/sdk/gre' 3 | 4 | greTask('migrate', 'Deploy protocol contracts') 5 | .addFlag('skipConfirmation', 'Skip confirmation prompt on write actions') 6 | .addFlag('skipPostDeploy', 'Skip accepting ownership and unpausing protocol after deploying') 7 | .addFlag('force', 'Deploy contract even if its already deployed') 8 | .addFlag('buildAcceptTx', '...') 9 | .setAction(async (taskArgs, hre) => { 10 | const graph = hre.graph(taskArgs) 11 | 12 | await deployGraphNetwork( 13 | taskArgs.addressBook, 14 | taskArgs.graphConfig, 15 | graph.chainId as GraphChainId, // TODO: fix type 16 | await graph.getDeployer(), 17 | graph.provider, 18 | { 19 | governor: taskArgs.skipPostDeploy ? undefined : (await graph.getNamedAccounts()).governor, 20 | forceDeploy: taskArgs.force, 21 | skipConfirmation: taskArgs.skipConfirmation, 22 | buildAcceptTx: taskArgs.buildAcceptTx, 23 | }, 24 | ) 25 | }) 26 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/allocationExchange.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { NamedAccounts } from '@graphprotocol/sdk/gre' 4 | 5 | describe('AllocationExchange configuration', () => { 6 | const { 7 | contracts: { AllocationExchange }, 8 | getNamedAccounts, 9 | } = hre.graph() 10 | 11 | let namedAccounts: NamedAccounts 12 | 13 | before(async () => { 14 | namedAccounts = await getNamedAccounts() 15 | }) 16 | 17 | it('should be owned by allocationExchangeOwner', async function () { 18 | const owner = await AllocationExchange.governor() 19 | expect(owner).eq(namedAccounts.allocationExchangeOwner.address) 20 | }) 21 | 22 | it('should accept vouchers from authority', async function () { 23 | const allowed = await AllocationExchange.authority(namedAccounts.authority.address) 24 | expect(allowed).eq(true) 25 | }) 26 | 27 | // graphToken and staking are private variables so we can't verify 28 | it.skip('graphToken should match the GraphToken deployment address') 29 | it.skip('staking should match the Staking deployment address') 30 | }) 31 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/epochManager.test.ts: -------------------------------------------------------------------------------- 1 | import { getItemValue } from '@graphprotocol/sdk' 2 | import { expect } from 'chai' 3 | import hre from 'hardhat' 4 | 5 | describe('EpochManager configuration', () => { 6 | const { 7 | graphConfig, 8 | contracts: { EpochManager, Controller }, 9 | } = hre.graph() 10 | 11 | it('should be controlled by Controller', async function () { 12 | const controller = await EpochManager.controller() 13 | expect(controller).eq(Controller.address) 14 | }) 15 | 16 | it('epochLength should match "lengthInBlocks" in the config file', async function () { 17 | const value = await EpochManager.epochLength() 18 | const expected = getItemValue(graphConfig, 'contracts/EpochManager/init/lengthInBlocks') 19 | expect(value).eq(expected) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/gns.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | 4 | describe('GNS configuration', () => { 5 | const { 6 | contracts: { Controller, GNS, SubgraphNFT }, 7 | } = hre.graph() 8 | 9 | it('should be controlled by Controller', async function () { 10 | const controller = await GNS.controller() 11 | expect(controller).eq(Controller.address) 12 | }) 13 | 14 | it('subgraphNFT should match the SubgraphNFT deployment address', async function () { 15 | const subgraphNFT = await GNS.subgraphNFT() 16 | expect(subgraphNFT).eq(SubgraphNFT.address) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/graphProxyAdmin.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { NamedAccounts } from '@graphprotocol/sdk/gre' 4 | 5 | describe('GraphProxyAdmin configuration', () => { 6 | const { 7 | contracts: { GraphProxyAdmin }, 8 | getNamedAccounts, 9 | } = hre.graph() 10 | 11 | let namedAccounts: NamedAccounts 12 | 13 | before(async () => { 14 | namedAccounts = await getNamedAccounts() 15 | }) 16 | 17 | it('should be owned by governor', async function () { 18 | const owner = await GraphProxyAdmin.governor() 19 | expect(owner).eq(namedAccounts.governor.address) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/graphToken.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { NamedAccounts } from '@graphprotocol/sdk/gre' 4 | 5 | describe('GraphToken configuration', () => { 6 | const { 7 | getNamedAccounts, 8 | contracts: { GraphToken }, 9 | getDeployer, 10 | } = hre.graph() 11 | 12 | let namedAccounts: NamedAccounts 13 | 14 | before(async () => { 15 | namedAccounts = await getNamedAccounts() 16 | }) 17 | 18 | it('should be owned by governor', async function () { 19 | const owner = await GraphToken.governor() 20 | expect(owner).eq(namedAccounts.governor.address) 21 | }) 22 | 23 | it('deployer should not be minter', async function () { 24 | const deployer = await getDeployer() 25 | const deployerIsMinter = await GraphToken.isMinter(deployer.address) 26 | expect(deployerIsMinter).eq(false) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l1/bridgeEscrow.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L1] BridgeEscrow configuration', function () { 6 | const graph = hre.graph() 7 | const { Controller, BridgeEscrow } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL2ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | it('should be controlled by Controller', async function () { 14 | const controller = await BridgeEscrow.controller() 15 | expect(controller).eq(Controller.address) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l1/graphToken.test.ts: -------------------------------------------------------------------------------- 1 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 3 | import { expect } from 'chai' 4 | import hre from 'hardhat' 5 | 6 | describe('[L1] GraphToken', () => { 7 | const graph = hre.graph() 8 | const { GraphToken, RewardsManager } = graph.contracts 9 | 10 | let unauthorized: SignerWithAddress 11 | 12 | before(async function () { 13 | if (isGraphL2ChainId(graph.chainId)) this.skip() 14 | unauthorized = (await graph.getTestAccounts())[0] 15 | }) 16 | 17 | describe('calls with unauthorized user', () => { 18 | it('mint should revert', async function () { 19 | const tx = GraphToken.connect(unauthorized).mint( 20 | unauthorized.address, 21 | '1000000000000000000000', 22 | ) 23 | await expect(tx).revertedWith('Only minter can call') 24 | }) 25 | 26 | it('RewardsManager should be minter', async function () { 27 | const rewardsMgrIsMinter = await GraphToken.isMinter(RewardsManager.address) 28 | expect(rewardsMgrIsMinter).eq(true) 29 | }) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l1/l1GNS.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L1] GNS', () => { 6 | const graph = hre.graph() 7 | const { L1GNS, L1GraphTokenGateway } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL2ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | describe('L1GNS', () => { 14 | it('counterpartGNSAddress should match the L2GNS address', async () => { 15 | const l2GNS = await L1GNS.counterpartGNSAddress() 16 | expect(l2GNS).eq(graph.l2.contracts.L2GNS.address) 17 | }) 18 | 19 | it('should be added to callhookAllowlist', async () => { 20 | const isAllowed = await L1GraphTokenGateway.callhookAllowlist(L1GNS.address) 21 | expect(isAllowed).true 22 | }) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l1/l1Staking.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L1] Staking', () => { 6 | const graph = hre.graph() 7 | const { L1Staking, L1GraphTokenGateway } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL2ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | describe('L1Staking', () => { 14 | it('counterpartStakingAddress should match the L2Staking address', async () => { 15 | // counterpartStakingAddress is internal so we access the storage directly 16 | const l2StakingData = await hre.ethers.provider.getStorageAt(L1Staking.address, 24) 17 | const l2Staking = hre.ethers.utils.defaultAbiCoder.decode(['address'], l2StakingData)[0] 18 | expect(l2Staking).eq(graph.l2.contracts.L2Staking.address) 19 | }) 20 | 21 | it('should be added to callhookAllowlist', async () => { 22 | const isAllowed = await L1GraphTokenGateway.callhookAllowlist(L1Staking.address) 23 | expect(isAllowed).true 24 | }) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l1/rewardsManager.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 4 | import { NamedAccounts } from '@graphprotocol/sdk/gre' 5 | 6 | describe('[L1] RewardsManager configuration', () => { 7 | const graph = hre.graph() 8 | const { RewardsManager } = graph.contracts 9 | 10 | let namedAccounts: NamedAccounts 11 | 12 | before(async function () { 13 | if (isGraphL2ChainId(graph.chainId)) this.skip() 14 | namedAccounts = await graph.getNamedAccounts() 15 | }) 16 | 17 | it('issuancePerBlock should match "issuancePerBlock" in the config file', async function () { 18 | const value = await RewardsManager.issuancePerBlock() 19 | expect(value).eq('114693500000000000000') // hardcoded as it's set with a function call rather than init parameter 20 | }) 21 | 22 | it('should allow subgraph availability oracle to deny rewards', async function () { 23 | const availabilityOracle = await RewardsManager.subgraphAvailabilityOracle() 24 | expect(availabilityOracle).eq(namedAccounts.availabilityOracle.address) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l2/l2GNS.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL1ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L2] GNS', () => { 6 | const graph = hre.graph() 7 | const { L2GNS } = graph.l2.contracts 8 | 9 | before(function () { 10 | if (isGraphL1ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | describe('L2GNS', () => { 14 | it('counterpartGNSAddress should match the L1GNS address', async () => { 15 | const l1GNS = await L2GNS.counterpartGNSAddress() 16 | expect(l1GNS).eq(graph.l1.contracts.L1GNS.address) 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l2/l2Staking.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL1ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L2] Staking', () => { 6 | const graph = hre.graph() 7 | const { L2Staking } = graph.l2.contracts 8 | 9 | before(function () { 10 | if (isGraphL1ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | describe('L2Staking', () => { 14 | it('counterpartStakingAddress should match the L1Staking address', async () => { 15 | // counterpartStakingAddress is internal so we access the storage directly 16 | const l1StakingData = await hre.ethers.provider.getStorageAt(L2Staking.address, 24) 17 | const l1Staking = hre.ethers.utils.defaultAbiCoder.decode(['address'], l1StakingData)[0] 18 | expect(l1Staking).eq(graph.l1.contracts.L1Staking.address) 19 | }) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/l2/rewardsManager.test.ts: -------------------------------------------------------------------------------- 1 | import { isGraphL1ChainId } from '@graphprotocol/sdk' 2 | import { expect } from 'chai' 3 | import hre from 'hardhat' 4 | 5 | describe('[L2] RewardsManager configuration', () => { 6 | const graph = hre.graph() 7 | const { RewardsManager, SubgraphAvailabilityManager } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL1ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | it('issuancePerBlock should be zero', async function () { 14 | const value = await RewardsManager.issuancePerBlock() 15 | expect(value).eq('6036500000000000000') // hardcoded as it's set with a function call rather than init parameter 16 | }) 17 | 18 | it('should allow subgraph availability manager to deny rewards', async function () { 19 | const availabilityOracle = await RewardsManager.subgraphAvailabilityOracle() 20 | expect(availabilityOracle).eq(SubgraphAvailabilityManager.address) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/rewardsManager.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | 4 | describe('RewardsManager configuration', () => { 5 | const { 6 | contracts: { RewardsManager, Controller }, 7 | } = hre.graph() 8 | 9 | it('should be controlled by Controller', async function () { 10 | const controller = await RewardsManager.controller() 11 | expect(controller).eq(Controller.address) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/serviceRegistry.test..ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | 4 | describe('ServiceRegistry configuration', () => { 5 | const { 6 | contracts: { ServiceRegistry, Controller }, 7 | } = hre.graph() 8 | 9 | it('should be controlled by Controller', async function () { 10 | const controller = await ServiceRegistry.controller() 11 | expect(controller).eq(Controller.address) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/config/subgraphNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { NamedAccounts } from '@graphprotocol/sdk/gre' 4 | 5 | describe('SubgraphNFT configuration', () => { 6 | const { 7 | getNamedAccounts, 8 | contracts: { SubgraphNFT, GNS, SubgraphNFTDescriptor }, 9 | } = hre.graph() 10 | 11 | let namedAccounts: NamedAccounts 12 | 13 | before(async () => { 14 | namedAccounts = await getNamedAccounts() 15 | }) 16 | 17 | it('should be owned by governor', async function () { 18 | const owner = await SubgraphNFT.governor() 19 | expect(owner).eq(namedAccounts.governor.address) 20 | }) 21 | 22 | it('should allow GNS to mint NFTs', async function () { 23 | const minter = await SubgraphNFT.minter() 24 | expect(minter).eq(GNS.address) 25 | }) 26 | 27 | it('tokenDescriptor should match the SubgraphNFTDescriptor deployment address', async function () { 28 | const tokenDescriptor = await SubgraphNFT.tokenDescriptor() 29 | expect(tokenDescriptor).eq(SubgraphNFTDescriptor.address) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/init/allocationExchange.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | 4 | describe('AllocationExchange initialization', () => { 5 | const { 6 | contracts: { AllocationExchange, GraphToken, Staking }, 7 | } = hre.graph() 8 | 9 | it('should allow Staking contract to spend MAX_UINT256 tokens on AllocationExchange behalf', async function () { 10 | const allowance = await GraphToken.allowance(AllocationExchange.address, Staking.address) 11 | expect(allowance).eq(hre.ethers.constants.MaxUint256) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/init/gns.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | 4 | describe('GNS initialization', () => { 5 | const { 6 | contracts: { GNS, GraphToken, Curation }, 7 | } = hre.graph() 8 | 9 | it('should allow Curation contract to spend MAX_UINT256 tokens on GNS behalf', async function () { 10 | const allowance = await GraphToken.allowance(GNS.address, Curation.address) 11 | expect(allowance).eq(hre.ethers.constants.MaxUint256) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/init/l1/bridgeEscrow.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL2ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L1] BridgeEscrow initialization', () => { 6 | const graph = hre.graph() 7 | const { BridgeEscrow, GraphToken, L1GraphTokenGateway } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL2ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | it('should allow L1GraphTokenGateway contract to spend MAX_UINT256 tokens on BridgeEscrow\'s behalf', async function () { 14 | const allowance = await GraphToken.allowance(BridgeEscrow.address, L1GraphTokenGateway.address) 15 | expect(allowance).eq(hre.ethers.constants.MaxUint256) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/init/l1/graphToken.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { getItemValue, isGraphL2ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L1] GraphToken initialization', () => { 6 | const graph = hre.graph() 7 | const { GraphToken } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL2ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | it('total supply should match "initialSupply" on the config file', async function () { 14 | const value = await GraphToken.totalSupply() 15 | const expected = getItemValue(graph.graphConfig, 'contracts/GraphToken/init/initialSupply') 16 | expect(value).eq(expected) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/deployment/init/l2/graphToken.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { isGraphL1ChainId } from '@graphprotocol/sdk' 4 | 5 | describe('[L2] GraphToken initialization', () => { 6 | const graph = hre.graph() 7 | const { GraphToken } = graph.contracts 8 | 9 | before(function () { 10 | if (isGraphL1ChainId(graph.chainId)) this.skip() 11 | }) 12 | 13 | it('total supply should be zero', async function () { 14 | const value = await GraphToken.totalSupply() 15 | expect(value).eq(0) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/close-allocations.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { AllocationFixture, getIndexerFixtures, IndexerFixture } from './fixtures/indexers' 4 | 5 | enum AllocationState { 6 | Null, 7 | Active, 8 | Closed, 9 | } 10 | 11 | let indexerFixtures: IndexerFixture[] 12 | 13 | describe('Close allocations', () => { 14 | const { contracts, getTestAccounts } = hre.graph() 15 | const { Staking } = contracts 16 | 17 | before(async () => { 18 | indexerFixtures = getIndexerFixtures(await getTestAccounts()) 19 | }) 20 | 21 | describe('Allocations', () => { 22 | let allocations: AllocationFixture[] = [] 23 | let openAllocations: AllocationFixture[] = [] 24 | let closedAllocations: AllocationFixture[] = [] 25 | 26 | before(() => { 27 | allocations = indexerFixtures.map(i => i.allocations).flat() 28 | openAllocations = allocations.filter(a => !a.close) 29 | closedAllocations = allocations.filter(a => a.close) 30 | }) 31 | 32 | it(`some allocatons should be open`, async function () { 33 | for (const allocation of openAllocations) { 34 | const state = await Staking.getAllocationState(allocation.signer.address) 35 | expect(state).eq(AllocationState.Active) 36 | } 37 | }) 38 | 39 | it(`some allocatons should be closed`, async function () { 40 | for (const allocation of closedAllocations) { 41 | const state = await Staking.getAllocationState(allocation.signer.address) 42 | expect(state).eq(AllocationState.Closed) 43 | } 44 | }) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/fixtures/bridge.ts: -------------------------------------------------------------------------------- 1 | import { toGRT } from '@graphprotocol/sdk' 2 | import { BigNumber } from 'ethers' 3 | 4 | import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 5 | 6 | export interface BridgeFixture { 7 | deploymentFile: string 8 | funder: SignerWithAddress 9 | accountsToFund: { 10 | signer: SignerWithAddress 11 | amount: BigNumber 12 | }[] 13 | } 14 | 15 | // Signers 16 | // 0: l1Deployer 17 | // 1: l2Deployer 18 | 19 | export const getBridgeFixture = (signers: SignerWithAddress[]): BridgeFixture => { 20 | return { 21 | deploymentFile: 'localNetwork.json', 22 | funder: signers[0], 23 | accountsToFund: [ 24 | { 25 | signer: signers[1], 26 | amount: toGRT(10_000_000), 27 | }, 28 | ], 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/fixtures/subgraphs.ts: -------------------------------------------------------------------------------- 1 | import { toGRT } from '@graphprotocol/sdk' 2 | import { BigNumber } from 'ethers' 3 | 4 | import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 5 | 6 | export interface SubgraphOwnerFixture { 7 | signer: SignerWithAddress 8 | ethBalance: BigNumber 9 | grtBalance: BigNumber 10 | } 11 | 12 | export interface SubgraphFixture { 13 | deploymentId: string 14 | subgraphId: string | null 15 | } 16 | 17 | // Test account indexes 18 | // 2: subgraphOwner 19 | export const getSubgraphOwner = (signers: SignerWithAddress[]): SubgraphOwnerFixture => { 20 | return { 21 | signer: signers[2], 22 | ethBalance: toGRT(0.1), 23 | grtBalance: toGRT(100_000), 24 | } 25 | } 26 | 27 | export const getSubgraphFixtures = (): SubgraphFixture[] => [ 28 | { 29 | deploymentId: '0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a', 30 | subgraphId: null, 31 | }, 32 | { 33 | deploymentId: '0x0653445635cc1d06bd2370d2a9a072406a420d86e7fa13ea5cde100e2108b527', 34 | subgraphId: null, 35 | }, 36 | { 37 | deploymentId: '0x3093dadafd593b5c2d10c16bf830e96fc41ea7b91d7dabd032b44331fb2a7e51', 38 | subgraphId: null, 39 | }, 40 | { 41 | deploymentId: '0xb3fc2abc303c70a16ab9d5fc38d7e8aeae66593a87a3d971b024dd34b97e94b1', 42 | subgraphId: null, 43 | }, 44 | ] 45 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/open-allocations.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { AllocationState } from '@graphprotocol/sdk' 4 | 5 | import { getIndexerFixtures, IndexerFixture } from './fixtures/indexers' 6 | 7 | let indexerFixtures: IndexerFixture[] 8 | 9 | describe('Open allocations', () => { 10 | const { contracts, getTestAccounts } = hre.graph() 11 | const { GraphToken, Staking } = contracts 12 | 13 | before(async () => { 14 | indexerFixtures = getIndexerFixtures(await getTestAccounts()) 15 | }) 16 | 17 | describe('GRT balances', () => { 18 | it(`indexer balances should match airdropped amount minus staked`, async function () { 19 | for (const indexer of indexerFixtures) { 20 | const address = indexer.signer.address 21 | const balance = await GraphToken.balanceOf(address) 22 | expect(balance).eq(indexer.grtBalance.sub(indexer.stake)) 23 | } 24 | }) 25 | }) 26 | 27 | describe('Staking', () => { 28 | it(`indexers should have staked tokens`, async function () { 29 | for (const indexer of indexerFixtures) { 30 | const address = indexer.signer.address 31 | const tokensStaked = (await Staking.stakes(address)).tokensStaked 32 | expect(tokensStaked).eq(indexer.stake) 33 | } 34 | }) 35 | }) 36 | 37 | describe('Allocations', () => { 38 | it(`allocations should be open`, async function () { 39 | const allocations = indexerFixtures.map(i => i.allocations).flat() 40 | for (const allocation of allocations) { 41 | const state = await Staking.getAllocationState(allocation.signer.address) 42 | expect(state).eq(AllocationState.Active) 43 | } 44 | }) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/send-grt-to-l2.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import hre from 'hardhat' 3 | import { BridgeFixture, getBridgeFixture } from './fixtures/bridge' 4 | 5 | describe('Bridge GRT to L2', () => { 6 | const graph = hre.graph() 7 | let bridgeFixture: BridgeFixture 8 | 9 | before(async () => { 10 | const l1Deployer = await graph.l1.getDeployer() 11 | const l2Deployer = await graph.l2.getDeployer() 12 | bridgeFixture = getBridgeFixture([l1Deployer, l2Deployer]) 13 | }) 14 | 15 | describe('GRT balances', () => { 16 | it(`L2 balances should match bridged amount`, async function () { 17 | for (const account of bridgeFixture.accountsToFund) { 18 | const l2GrtBalance = await graph.l2.contracts.GraphToken.balanceOf(account.signer.address) 19 | expect(l2GrtBalance).eq(account.amount) 20 | } 21 | }) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/scenarios/send-grt-to-l2.ts: -------------------------------------------------------------------------------- 1 | // ### Scenario description ### 2 | // Bridge action > Bridge GRT tokens from L1 to L2 3 | // This scenario will bridge GRT tokens from L1 to L2. See fixtures for details. 4 | // Run with: 5 | // npx hardhat e2e:scenario send-grt-to-l2 --network --graph-config config/graph..yml 6 | 7 | import hre from 'hardhat' 8 | import { getBridgeFixture } from './fixtures/bridge' 9 | import { getGREOptsFromArgv } from '@graphprotocol/sdk/gre' 10 | import { ethers } from 'ethers' 11 | 12 | async function main() { 13 | const graphOpts = getGREOptsFromArgv() 14 | const graph = hre.graph(graphOpts) 15 | 16 | const l1Deployer = await graph.l1.getDeployer() 17 | const l2Deployer = await graph.l2.getDeployer() 18 | 19 | const bridgeFixture = getBridgeFixture([l1Deployer, l2Deployer]) 20 | 21 | // == Send GRT to L2 accounts 22 | for (const account of bridgeFixture.accountsToFund) { 23 | await hre.run('bridge:send-to-l2', { 24 | ...graphOpts, 25 | amount: ethers.utils.formatEther(account.amount), 26 | sender: bridgeFixture.funder.address, 27 | recipient: account.signer.address, 28 | deploymentFile: bridgeFixture.deploymentFile, 29 | }) 30 | } 31 | } 32 | 33 | // We recommend this pattern to be able to use async/await everywhere 34 | // and properly handle errors. 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch((error) => { 38 | console.error(error) 39 | process.exitCode = 1 40 | }) 41 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/example/Instructions.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | 1) Upgrade the GNS contract, add a `uint256 public test;` storage variable 4 | 2) Run the upgrade script: 5 | ``` 6 | CHAIN_ID=1 FORK_URL= CONTRACT_NAME=GNS UPGRADE_NAME=example yarn test:upgrade 7 | ``` -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/example/post-upgrade.test.ts: -------------------------------------------------------------------------------- 1 | import chai, { expect } from 'chai' 2 | import chaiAsPromised from 'chai-as-promised' 3 | import hre from 'hardhat' 4 | 5 | chai.use(chaiAsPromised) 6 | 7 | describe('GNS contract', () => { 8 | it(`'test' storage variable should exist`, async function () { 9 | const graph = hre.graph() 10 | const { GNS } = graph.contracts 11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 12 | // @ts-ignore (we know this property doesn't exist) 13 | await expect(GNS.test()).to.eventually.be.fulfilled 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/example/post-upgrade.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | /* eslint-disable @typescript-eslint/require-await */ 3 | // REMOVE the above lines 4 | 5 | import hre from 'hardhat' 6 | import { getGREOptsFromArgv } from '@graphprotocol/sdk/gre' 7 | 8 | async function main() { 9 | const graphOpts = getGREOptsFromArgv() 10 | const graph = hre.graph(graphOpts) 11 | console.log('Hello from the post-upgrade script!') 12 | } 13 | 14 | // We recommend this pattern to be able to use async/await everywhere 15 | // and properly handle errors. 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error) 20 | process.exitCode = 1 21 | }) 22 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/example/pre-upgrade.test.ts: -------------------------------------------------------------------------------- 1 | import chai, { expect } from 'chai' 2 | import chaiAsPromised from 'chai-as-promised' 3 | import hre from 'hardhat' 4 | 5 | chai.use(chaiAsPromised) 6 | 7 | describe('GNS contract', () => { 8 | it(`'test' storage variable should not exist`, async function () { 9 | const graph = hre.graph() 10 | const { GNS } = graph.contracts 11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 12 | // @ts-ignore (we know this property doesn't exist) 13 | await expect(GNS.test()).to.eventually.be.rejected 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/example/pre-upgrade.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | /* eslint-disable @typescript-eslint/require-await */ 3 | // REMOVE the above lines 4 | 5 | import hre from 'hardhat' 6 | import { getGREOptsFromArgv } from '@graphprotocol/sdk/gre' 7 | 8 | async function main() { 9 | const graphOpts = getGREOptsFromArgv() 10 | const graph = hre.graph(graphOpts) 11 | console.log('Hello from the pre-upgrade script!') 12 | } 13 | 14 | // We recommend this pattern to be able to use async/await everywhere 15 | // and properly handle errors. 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error) 20 | process.exitCode = 1 21 | }) 22 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/exponential-rebates/Instructions.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Run with: 4 | 5 | ``` 6 | CHAIN_ID=1 \ 7 | FORK_URL=https://mainnet.infura.io/v3/ \ 8 | FORK_BLOCK_NUMBER=17324022 \ 9 | CONTRACT_NAME=L1Staking \ 10 | UPGRADE_NAME=exponential-rebates \ 11 | yarn test:upgrade 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/exponential-rebates/fixtures/allocations.ts: -------------------------------------------------------------------------------- 1 | // Valid allocation states for 2 | // - chain: Ethereum Mainnet 3 | // - block number: 17324022 4 | // Allocation ids obtained from network subgraph 5 | 6 | import { AllocationState } from '@graphprotocol/sdk' 7 | 8 | export default [ 9 | { id: '0x00b7a526e1e42ba1f14e69f487aad31350164a9e', state: AllocationState.Null }, 10 | { id: '0x00b7a526e1e42ba1f14e69f487aad31350164a9f', state: AllocationState.Null }, 11 | { id: '0x00b7a526e1e42ba1f14e69f487aad31350164a90', state: AllocationState.Null }, 12 | { id: '0x00b7a526e1e42ba1f14e69f487aad31350164a9d', state: AllocationState.Active }, 13 | { id: '0x02a5e2312af00aa85a24cf4c43a8c0a6fd9a6c2d', state: AllocationState.Active }, 14 | { id: '0x0a272f72c14a226525fb4e2114f8a0052dc7dd38', state: AllocationState.Active }, 15 | { id: '0x016ad691b2572ed3192e366584d12e94699e12b2', state: AllocationState.Closed }, 16 | { id: '0x060df24858f3aa6d445645b73d0d2eeb117ae8a3', state: AllocationState.Closed }, 17 | { id: '0x08ee64a4505e9cd77f0cae15c56e795dca7384e3', state: AllocationState.Closed }, 18 | { id: '0x03f9e610fea2f8eab7321038997a50fe4ecc6aa5', state: AllocationState.Finalized }, 19 | { id: '0x0989e792c6ca9eb0a0f2f63d92e407cdc1e64c29', state: AllocationState.Finalized }, 20 | { id: '0x0d62657d6b75f462b28c000f6f6e41d56cc60069', state: AllocationState.Finalized }, 21 | { id: '0x0da397c2887632e7250a5f1a8a7ed56e437780f5', state: AllocationState.Claimed }, 22 | { id: '0x0d819c0e05782f41a4ab22fe9b5d439235093706', state: AllocationState.Claimed }, 23 | { id: '0x0afef3ebeb9f85ce60c89ecaa7d98e41335ce5a4', state: AllocationState.Claimed }, 24 | ] 25 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/exponential-rebates/post-upgrade.ts: -------------------------------------------------------------------------------- 1 | import hre from 'hardhat' 2 | import { getGREOptsFromArgv } from '@graphprotocol/sdk/gre' 3 | 4 | async function main() { 5 | const graphOpts = getGREOptsFromArgv() 6 | const graph = hre.graph(graphOpts) 7 | console.log('Hello from the post-upgrade script!') 8 | 9 | // TODO: remove this hack 10 | // mainnet does not have staking extension as of now 11 | // We set it to a random contract, otherwise it uses 0x00 12 | // which does not revert when called with calldata 13 | const { governor } = await graph.getNamedAccounts() 14 | await graph.contracts.Staking.connect(governor).setExtensionImpl( 15 | '0xc944E90C64B2c07662A292be6244BDf05Cda44a7', 16 | ) 17 | } 18 | 19 | // We recommend this pattern to be able to use async/await everywhere 20 | // and properly handle errors. 21 | main() 22 | .then(() => process.exit(0)) 23 | .catch((error) => { 24 | console.error(error) 25 | process.exitCode = 1 26 | }) 27 | -------------------------------------------------------------------------------- /packages/contracts/test/e2e/upgrades/exponential-rebates/pre-upgrade.ts: -------------------------------------------------------------------------------- 1 | import hre, { ethers } from 'hardhat' 2 | import { getGREOptsFromArgv } from '@graphprotocol/sdk/gre' 3 | 4 | async function main() { 5 | const graphOpts = getGREOptsFromArgv() 6 | const graph = hre.graph(graphOpts) 7 | const { GraphToken, Staking } = graph.contracts 8 | 9 | console.log('Hello from the pre-upgrade script!') 10 | 11 | // Make the deployer an asset holder 12 | const deployer = await graph.getDeployer() 13 | const { governor } = await graph.getNamedAccounts() 14 | // @ts-expect-error asset holder existed back then 15 | await Staking.connect(governor).setAssetHolder(deployer.address, true) 16 | 17 | // Get some funds on the deployer 18 | await GraphToken.connect(governor).transfer(deployer.address, ethers.utils.parseEther('100000')) 19 | await graph.provider.send('hardhat_setBalance', [deployer.address, '0x56BC75E2D63100000']) // 100 Eth 20 | 21 | // Approve Staking contract to pull GRT from new asset holder 22 | await GraphToken.connect(deployer).approve(Staking.address, ethers.utils.parseEther('100000')) 23 | } 24 | 25 | // We recommend this pattern to be able to use async/await everywhere 26 | // and properly handle errors. 27 | main() 28 | .then(() => process.exit(0)) 29 | .catch((error) => { 30 | console.error(error) 31 | process.exitCode = 1 32 | }) 33 | -------------------------------------------------------------------------------- /packages/contracts/test/unit/disputes/common.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { Attestation, Receipt } from '@graphprotocol/common-ts' 3 | 4 | export const MAX_PPM = 1000000 5 | 6 | const { defaultAbiCoder: abi, arrayify, concat, hexlify, solidityKeccak256, joinSignature } = utils 7 | 8 | export interface Dispute { 9 | id: string 10 | attestation: Attestation 11 | encodedAttestation: string 12 | indexerAddress: string 13 | receipt: Receipt 14 | } 15 | 16 | export function createQueryDisputeID( 17 | attestation: Attestation, 18 | indexerAddress: string, 19 | submitterAddress: string, 20 | ): string { 21 | return solidityKeccak256( 22 | ['bytes32', 'bytes32', 'bytes32', 'address', 'address'], 23 | [ 24 | attestation.requestCID, 25 | attestation.responseCID, 26 | attestation.subgraphDeploymentID, 27 | indexerAddress, 28 | submitterAddress, 29 | ], 30 | ) 31 | } 32 | 33 | export function encodeAttestation(attestation: Attestation): string { 34 | const data = arrayify( 35 | abi.encode( 36 | ['bytes32', 'bytes32', 'bytes32'], 37 | [attestation.requestCID, attestation.responseCID, attestation.subgraphDeploymentID], 38 | ), 39 | ) 40 | const sig = joinSignature(attestation) 41 | return hexlify(concat([data, sig])) 42 | } 43 | -------------------------------------------------------------------------------- /packages/contracts/test/unit/graphToken.test.ts: -------------------------------------------------------------------------------- 1 | import { grtTests } from './lib/graphTokenTests' 2 | 3 | describe('GraphToken', () => { 4 | grtTests.bind(this)(false) 5 | }) 6 | -------------------------------------------------------------------------------- /packages/contracts/test/unit/l2/l2ArbitrumMessengerMock.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Mock implementation of the L2ArbitrumMessenger contract 3 | * This is used to override the sendTxToL1 function in the L2GraphTokenGateway contract 4 | */ 5 | export class L2ArbitrumMessengerMock { 6 | private static _calls: Array<{ 7 | l1CallValue: number 8 | from: string 9 | to: string 10 | data: string 11 | }> = [] 12 | 13 | /** 14 | * Mock implementation of sendTxToL1 function 15 | * @param l1CallValue The call value to send to L1 16 | * @param from The sender address 17 | * @param to The destination address on L1 18 | * @param data The calldata to send to L1 19 | * @returns A transaction ID (always returns 1) 20 | */ 21 | public static sendTxToL1(l1CallValue: number, from: string, to: string, data: string): number { 22 | this._calls.push({ l1CallValue, from, to, data }) 23 | return 1 // Always return 1 as the transaction ID 24 | } 25 | 26 | /** 27 | * Check if sendTxToL1 was called with specific arguments 28 | * @param to The expected destination address 29 | * @param data The expected calldata 30 | * @returns true if the function was called with the specified arguments 31 | */ 32 | public static calledWith(to: string, data: string): boolean { 33 | return this._calls.some((call) => call.to === to && call.data === data) 34 | } 35 | 36 | /** 37 | * Reset all recorded calls 38 | */ 39 | public static reset(): void { 40 | this._calls = [] 41 | } 42 | 43 | /** 44 | * Get the number of times sendTxToL1 was called 45 | */ 46 | public static get callCount(): number { 47 | return this._calls.length 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/contracts/truffle.js: -------------------------------------------------------------------------------- 1 | // Needed for truffle flattener 2 | module.exports = { 3 | compilers: { 4 | solc: { 5 | version: '0.7.3', 6 | settings: { 7 | optimizer: { 8 | enabled: true, 9 | runs: 200, 10 | }, 11 | }, 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /packages/contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true, 10 | "incremental": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/data-edge/.env.sample: -------------------------------------------------------------------------------- 1 | MNEMONIC= 2 | INFURA_KEY= 3 | ETHERSCAN_API_KEY= 4 | ARBISCAN_API_KEY= 5 | -------------------------------------------------------------------------------- /packages/data-edge/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.markdownlint.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/data-edge/.solcover.js: -------------------------------------------------------------------------------- 1 | const skipFiles = [''] 2 | 3 | module.exports = { 4 | providerOptions: { 5 | mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', 6 | network_id: 1337, 7 | }, 8 | skipFiles, 9 | istanbulFolder: './reports/coverage', 10 | } 11 | -------------------------------------------------------------------------------- /packages/data-edge/README.md: -------------------------------------------------------------------------------- 1 | # Data Edge 2 | 3 | A DataEdge contract is used to store arbitrary data on-chain on any EVM compatible blockchain. A subgraph can then read all the calldata sent to a particular contract, decode it and update the subgraph state accordingly. 4 | 5 | The DataEdge accepts any function call by using a fallback function that will not revert. It is up to the implementer to define the calldata format as well as how to decode it. 6 | 7 | ### Additional Considerations 8 | 9 | - Fallback is not payable to avoid anyone sending ETH by mistake as the main purpose is to store calldata. 10 | 11 | # Deploying 12 | 13 | Setup a `.env` file with the keys you want to use for deployments. You can use `.env.sample` as a guide. 14 | Deploy a `DataEdge` contract by running `yarn deploy -- --network ` 15 | 16 | # Copyright 17 | 18 | Copyright © 2022 The Graph Foundation 19 | 20 | Licensed under [GPL license](LICENSE). 21 | -------------------------------------------------------------------------------- /packages/data-edge/addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "EBODataEdge": "0xADE906194C923b28F03F48BC5D9D987AAE21fFab" 4 | }, 5 | "42161": { 6 | "EBOEventfulDataEdge": "0x633bb9790d7c4c59991cebd377c0ed6501a35ebe", 7 | "SAOEventfulDataEdge": "0xeD16cEbd4fa74a0016E1149cc03563Db4B223aec" 8 | }, 9 | "421614": { 10 | "EBOEventfulDataEdge": "0x9b9402939133F27c6eba81a321dfBFa1feE6714E", 11 | "SAOEventfulDataEdge": "0xB61AF143c79Cbdd68f179B657AaC86665CC2B469" 12 | }, 13 | "11155111": { 14 | "EBOEventfulDataEdge": "0xEFC8D47673777b899f2FB597C6FC0E87ecce98Cb" 15 | } 16 | } -------------------------------------------------------------------------------- /packages/data-edge/contracts/DataEdge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.12; 4 | 5 | /// @title Data Edge contract is only used to store on-chain data, it does not 6 | /// perform execution. On-chain client services can read the data 7 | /// and decode the payload for different purposes. 8 | contract DataEdge { 9 | /// @dev Fallback function, accepts any payload 10 | fallback() external payable { 11 | // no-op 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/data-edge/contracts/EventfulDataEdge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.12; 4 | 5 | /// @title Data Edge contract is only used to store on-chain data, it does not 6 | /// perform execution. On-chain client services can read the data 7 | /// and decode the payload for different purposes. 8 | /// NOTE: This version emits an event with the calldata. 9 | contract EventfulDataEdge { 10 | event Log(bytes data); 11 | 12 | /// @dev Fallback function, accepts any payload 13 | fallback() external payable { 14 | emit Log(msg.data); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/data-edge/prettier.config.cjs: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../prettier.config.cjs') 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | } 6 | -------------------------------------------------------------------------------- /packages/data-edge/scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | # Build 6 | yarn compile -------------------------------------------------------------------------------- /packages/data-edge/scripts/coverage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | yarn compile 6 | npx hardhat coverage $@ -------------------------------------------------------------------------------- /packages/data-edge/scripts/flatten: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUT_DIR="build/flatten" 4 | 5 | mkdir -p ${OUT_DIR} 6 | 7 | echo "Flattening contracts..." 8 | 9 | FILES=( 10 | "contracts/Counter.sol" 11 | ) 12 | 13 | for path in ${FILES[@]}; do 14 | IFS='/' 15 | parts=( $path ) 16 | name=${parts[${#parts[@]}-1]} 17 | echo "Flatten > ${name}" 18 | hardhat flatten "${path}" > "${OUT_DIR}/${name}" 19 | done 20 | 21 | echo "Done!" 22 | -------------------------------------------------------------------------------- /packages/data-edge/scripts/prepublish: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TYPECHAIN_DIR=dist/types 4 | 5 | set -eo pipefail 6 | 7 | # Build contracts 8 | yarn clean 9 | yarn build 10 | 11 | # Refresh distribution folder 12 | rm -rf dist && mkdir -p dist/types/_src 13 | cp -R build/abis/ dist/abis 14 | cp -R build/types/ dist/types/_src 15 | 16 | ### Build Typechain bindings 17 | 18 | # Build and create TS declarations 19 | tsc -d ${TYPECHAIN_DIR}/_src/*.ts --outdir ${TYPECHAIN_DIR} 20 | # Copy back sources 21 | cp ${TYPECHAIN_DIR}/_src/*.ts ${TYPECHAIN_DIR} 22 | # Delete temporary src dir 23 | rm -rf ${TYPECHAIN_DIR}/_src -------------------------------------------------------------------------------- /packages/data-edge/scripts/security: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Before running: 4 | # This tool requires to have solc installed. 5 | # Ensure that you have the binaries installed by pip3 in your path. 6 | # Install: https://github.com/crytic/slither#how-to-install 7 | # Usage: https://github.com/crytic/slither/wiki/Usage 8 | 9 | mkdir -p reports 10 | 11 | pip3 install --user slither-analyzer && \ 12 | yarn build && \ 13 | 14 | echo "Analyzing contracts..." 15 | slither . &> reports/analyzer-report.log && \ 16 | 17 | echo "Done!" 18 | -------------------------------------------------------------------------------- /packages/data-edge/scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect" 6 | TESTRPC_PORT=8545 7 | 8 | ### Functions 9 | 10 | evm_running() { 11 | nc -z localhost "$TESTRPC_PORT" 12 | } 13 | 14 | evm_start() { 15 | echo "Starting our own evm instance at port $TESTRPC_PORT" 16 | npx hardhat node --port "$TESTRPC_PORT" > /dev/null & 17 | } 18 | 19 | evm_kill() { 20 | if evm_running; then 21 | echo "Killing evm instance at port $TESTRPC_PORT" 22 | kill -9 $(lsof -i:$TESTRPC_PORT -t) 23 | fi 24 | } 25 | 26 | ### Setup EVM 27 | 28 | # Ensure we compiled sources 29 | 30 | yarn build 31 | 32 | # Gas reporter needs to run in its own evm instance 33 | if [ "$RUN_EVM" = true ]; then 34 | evm_kill 35 | evm_start 36 | sleep 5 37 | fi 38 | 39 | ### Main 40 | 41 | mkdir -p reports 42 | 43 | # Run using the standalone evm instance 44 | npx hardhat test --network hardhat 45 | 46 | ### Cleanup 47 | 48 | # Exit error mode so the evm instance always gets killed 49 | set +e 50 | result=0 51 | 52 | if [ "$RUN_EVM" = true ]; then 53 | evm_kill 54 | fi 55 | 56 | exit $result 57 | -------------------------------------------------------------------------------- /packages/data-edge/tasks/craft-calldata.ts: -------------------------------------------------------------------------------- 1 | import '@nomiclabs/hardhat-ethers' 2 | import { Contract } from 'ethers' 3 | import { task } from 'hardhat/config' 4 | 5 | const baseABI = [ 6 | { 7 | inputs: [ 8 | { 9 | internalType: 'bytes', 10 | name: '_payload', 11 | type: 'bytes', 12 | }, 13 | ], 14 | name: '', 15 | outputs: [], 16 | stateMutability: 'nonpayable', 17 | type: 'function', 18 | }, 19 | ] 20 | 21 | const getContract = (contractAddress: string, abi, provider) => { 22 | return new Contract(contractAddress, abi, provider) 23 | } 24 | 25 | const getAbiForSelector = (selector: string) => { 26 | return baseABI.map((item) => { 27 | item.name = selector 28 | return item 29 | }) 30 | } 31 | 32 | task('data:craft', 'Build calldata') 33 | .addParam('edge', 'Address of the data edge contract') 34 | .addParam('selector', 'Selector name') 35 | .addParam('data', 'Call data to post') 36 | .setAction(async (taskArgs, hre) => { 37 | // parse input 38 | const edgeAddress = taskArgs.edge 39 | const calldata = taskArgs.data 40 | const selector = taskArgs.selector 41 | 42 | // build data 43 | const abi = getAbiForSelector(selector) 44 | const contract = getContract(edgeAddress, abi, hre.ethers.provider) 45 | const tx = await contract.populateTransaction[selector](calldata) 46 | const txData = tx.data 47 | console.log(txData) 48 | }) 49 | -------------------------------------------------------------------------------- /packages/data-edge/tasks/post-calldata.ts: -------------------------------------------------------------------------------- 1 | import '@nomiclabs/hardhat-ethers' 2 | import { task } from 'hardhat/config' 3 | 4 | task('data:post', 'Post calldata') 5 | .addParam('edge', 'Address of the data edge contract') 6 | .addParam('data', 'Call data to post') 7 | .setAction(async (taskArgs, hre) => { 8 | // prepare data 9 | const edgeAddress = taskArgs.edge 10 | const txData = taskArgs.data 11 | const contract = await hre.ethers.getContractAt('DataEdge', edgeAddress) 12 | const txRequest = { 13 | data: txData, 14 | to: contract.address, 15 | } 16 | 17 | // send transaction 18 | console.log(`Sending data...`) 19 | console.log(`> edge: ${contract.address}`) 20 | console.log(`> sender: ${await contract.signer.getAddress()}`) 21 | console.log(`> payload: ${txData}`) 22 | const tx = await contract.signer.sendTransaction(txRequest) 23 | console.log(`> tx: ${tx.hash} nonce:${tx.nonce} limit: ${tx.gasLimit.toString()} gas: ${tx.gasPrice.toNumber() / 1e9} (gwei)`) 24 | const rx = await tx.wait() 25 | console.log('> rx: ', rx.status == 1 ? 'success' : 'failed') 26 | console.log(`Done!`) 27 | }) 28 | -------------------------------------------------------------------------------- /packages/data-edge/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true, 10 | "incremental": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/sdk/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.markdownlint.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/sdk/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register/files", 3 | "ignore": ["test/fixture-projects/**/*"], 4 | "timeout": 6000 5 | } 6 | -------------------------------------------------------------------------------- /packages/sdk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @graphprotocol/sdk 2 | 3 | ## 0.5.0 4 | 5 | ### Minor Changes 6 | 7 | - 554af2c: feat(utils): add utility to parse subgraph ids 8 | 9 | ### Patch Changes 10 | 11 | - c5641c5: Ensure L2 aliased addresses are the correct length 12 | - Updated dependencies 13 | - Updated dependencies [554af2c] 14 | - @graphprotocol/contracts@6.2.0 15 | -------------------------------------------------------------------------------- /packages/sdk/prettier.config.cjs: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../prettier.config.cjs') 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | } 6 | -------------------------------------------------------------------------------- /packages/sdk/src/chain/index.ts: -------------------------------------------------------------------------------- 1 | export { l1Chains, l2Chains, chains, l1ToL2, l2ToL1, counterpart } from './id' 2 | export { 3 | l1ChainNames, 4 | l2ChainNames, 5 | chainNames, 6 | l1ToL2Name, 7 | l2ToL1Name, 8 | counterpartName, 9 | } from './name' 10 | export { 11 | isGraphChainId, 12 | isGraphL1ChainId, 13 | isGraphL2ChainId, 14 | isGraphChainName, 15 | isGraphL1ChainName, 16 | isGraphL2ChainName, 17 | isGraphChainL1Localhost, 18 | isGraphChainL2Localhost, 19 | } from './types' 20 | 21 | export type { 22 | GraphChainId, 23 | GraphL1ChainId, 24 | GraphL2ChainId, 25 | GraphL1ChainName, 26 | GraphL2ChainName, 27 | } from './types' 28 | -------------------------------------------------------------------------------- /packages/sdk/src/chain/list.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Master chain list for all the chain pairs supported by the Graph Protocol 3 | * See {@link GraphChainPair} for details on the structure of a chain pair 4 | * @enum 5 | */ 6 | export const GraphChainList = [ 7 | { 8 | l1: { 9 | id: 1, 10 | name: 'mainnet', 11 | }, 12 | l2: { 13 | id: 42161, 14 | name: 'arbitrum-one', 15 | }, 16 | }, 17 | { 18 | l1: { 19 | id: 4, 20 | name: 'rinkeby', 21 | }, 22 | l2: { 23 | id: 421611, 24 | name: 'arbitrum-rinkeby', 25 | }, 26 | }, 27 | { 28 | l1: { 29 | id: 11155111, 30 | name: 'sepolia', 31 | }, 32 | l2: { 33 | id: 421614, 34 | name: 'arbitrum-sepolia', 35 | }, 36 | }, 37 | { 38 | l1: { 39 | id: 5, 40 | name: 'goerli', 41 | }, 42 | l2: { 43 | id: 421613, 44 | name: 'arbitrum-goerli', 45 | }, 46 | }, 47 | { 48 | l1: { 49 | id: 1337, 50 | name: 'localnitrol1', 51 | }, 52 | l2: { 53 | id: 412346, 54 | name: 'localnitrol2', 55 | }, 56 | }, 57 | ] as const 58 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/deploy/artifacts.ts: -------------------------------------------------------------------------------- 1 | import { Artifacts } from 'hardhat/internal/artifacts' 2 | import type { Artifact } from 'hardhat/types' 3 | 4 | /** 5 | * Load a contract's artifact from the build output folder 6 | * If multiple build output folders are provided, they will be searched in order 7 | * @param name Name of the contract 8 | * @param buildDir Path to the build output folder(s). Defaults to `artifacts`. 9 | * @returns The artifact corresponding to the contract name 10 | */ 11 | export const loadArtifact = (name: string, buildDir?: string[] | string): Artifact => { 12 | let artifacts: Artifacts | undefined 13 | let artifact: Artifact | undefined 14 | buildDir = buildDir ?? ['artifacts'] 15 | 16 | if (typeof buildDir === 'string') { 17 | buildDir = [buildDir] 18 | } 19 | 20 | for (const dir of buildDir) { 21 | try { 22 | artifacts = new Artifacts(dir) 23 | artifact = artifacts.readArtifactSync(name) 24 | break 25 | } catch (error) { 26 | const message = error instanceof Error ? error.message : error 27 | console.error(`Could not load artifact ${name} from ${dir} - ${message}`) 28 | } 29 | } 30 | 31 | if (artifact === undefined) { 32 | throw new Error(`Could not load artifact ${name}`) 33 | } 34 | 35 | return artifact 36 | } 37 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/deploy/factory.ts: -------------------------------------------------------------------------------- 1 | import { ContractFactory } from 'ethers' 2 | import { loadArtifact } from './artifacts' 3 | 4 | import type { Artifact } from 'hardhat/types' 5 | import type { Libraries } from '../types/artifacts' 6 | 7 | /** 8 | * Gets a contract factory for a given contract name 9 | * 10 | * @param name Name of the contract 11 | * @param libraries Libraries to link 12 | * @returns the contract factory 13 | */ 14 | export const getContractFactory = (name: string, libraries?: Libraries): ContractFactory => { 15 | const artifact = loadArtifact(name) 16 | // Fixup libraries 17 | if (libraries && Object.keys(libraries).length > 0) { 18 | artifact.bytecode = linkLibraries(artifact, libraries) 19 | } 20 | return new ContractFactory(artifact.abi, artifact.bytecode) 21 | } 22 | 23 | const linkLibraries = (artifact: Artifact, libraries?: Libraries): string => { 24 | let bytecode = artifact.bytecode 25 | 26 | if (libraries) { 27 | if (artifact.linkReferences) { 28 | for (const fileReferences of Object.values(artifact.linkReferences)) { 29 | for (const [libName, fixups] of Object.entries(fileReferences)) { 30 | const addr = libraries[libName] 31 | if (addr === undefined) { 32 | continue 33 | } 34 | 35 | for (const fixup of fixups) { 36 | bytecode = 37 | bytecode.substr(0, 2 + fixup.start * 2) + 38 | addr.substr(2) + 39 | bytecode.substr(2 + (fixup.start + fixup.length) * 2) 40 | } 41 | } 42 | } 43 | } 44 | } 45 | return bytecode 46 | } 47 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/types/address-book.ts: -------------------------------------------------------------------------------- 1 | import type { DeployResult } from './deploy' 2 | 3 | // TODO: doc this 4 | 5 | // JSON format: 6 | // { 7 | // "": { 8 | // "": {} 9 | // ... 10 | // } 11 | // } 12 | export type AddressBookJson< 13 | ChainId extends number = number, 14 | ContractName extends string = string, 15 | > = Record> 16 | 17 | export type ConstructorArg = string | Array 18 | 19 | export type AddressBookEntry = { 20 | address: string 21 | constructorArgs?: Array 22 | initArgs?: Array 23 | proxy?: boolean 24 | implementation?: AddressBookEntry 25 | } & Partial> 26 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/types/artifacts.ts: -------------------------------------------------------------------------------- 1 | export interface Libraries { 2 | [libraryName: string]: string 3 | } 4 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/types/config.ts: -------------------------------------------------------------------------------- 1 | import type { ContractParam } from './contract' 2 | 3 | export type ContractConfigParam = { name: string; value: string } 4 | export type ContractConfigCall = { fn: string; params: Array } 5 | export interface ContractConfig { 6 | params: Array 7 | calls: Array 8 | proxy: boolean 9 | } 10 | 11 | export interface ABRefReplace { 12 | ref: string 13 | replace: string 14 | } 15 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/types/contract.ts: -------------------------------------------------------------------------------- 1 | import type { BigNumber, Contract } from 'ethers' 2 | 3 | export type ContractList = Partial> 4 | 5 | export type ContractParam = string | BigNumber | number | Array 6 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/lib/types/deploy.ts: -------------------------------------------------------------------------------- 1 | import { AddressBook } from '../address-book' 2 | import { isSomeEnum } from '../../../utils/type-guard' 3 | 4 | import type { Contract, Signer } from 'ethers' 5 | import type { ContractParam } from './contract' 6 | import type { Libraries } from './artifacts' 7 | 8 | export enum DeployType { 9 | Deploy = 'deploy', 10 | DeployAndSave = 'deploy-save', 11 | DeployWithProxy = 'deploy-with-proxy', 12 | DeployWithProxyAndSave = 'deploy-with-proxy-save', 13 | DeployImplementationAndSave = 'deploy-implementation-save', 14 | } 15 | 16 | export type DeployData = { 17 | name: string 18 | args?: Array 19 | opts?: Record 20 | } 21 | 22 | export type DeployResult = { 23 | contract: Contract 24 | creationCodeHash: string 25 | runtimeCodeHash: string 26 | txHash: string 27 | libraries?: Libraries 28 | } 29 | 30 | // Utility type to add parameters to a function interface 31 | // https://stackoverflow.com/a/69668215 32 | type AddParameters any, TParameters extends [...args: any]> = ( 33 | ...args: [...Parameters, ...TParameters] 34 | ) => ReturnType 35 | 36 | export type DeployFunction = (sender: Signer, contract: DeployData) => Promise 37 | 38 | export type DeployAddressBookFunction = ( 39 | sender: Signer, 40 | contract: DeployData, 41 | addressBook: AddressBook, 42 | ) => Promise 43 | export type DeployAddressBookWithProxyFunction = AddParameters< 44 | DeployAddressBookFunction, 45 | [proxy: DeployData] 46 | > 47 | 48 | // ** Type guards ** 49 | export function isDeployType(value: unknown): value is DeployType { 50 | return isSomeEnum(DeployType)(value) 51 | } 52 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/logger.ts: -------------------------------------------------------------------------------- 1 | import debug from 'debug' 2 | 3 | const LOG_BASE = 'graph:deployments' 4 | export const logDebug = debug(`${LOG_BASE}:debug`) 5 | export const logInfo = debug(`${LOG_BASE}:info`) 6 | export const logWarn = debug(`${LOG_BASE}:warn`) 7 | export const logError = debug(`${LOG_BASE}:error`) 8 | 9 | // if (process.env.DEBUG === undefined) { 10 | // debug.enable(`${LOG_BASE}:info`) 11 | // } 12 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/network/actions/disputes.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createAttestation, 3 | encodeAttestation as encodeAttestationLib, 4 | Attestation, 5 | Receipt, 6 | } from '@graphprotocol/common-ts' 7 | import { GraphChainId } from '../../../chain' 8 | 9 | export async function buildAttestation( 10 | receipt: Receipt, 11 | signer: string, 12 | disputeManagerAddress: string, 13 | chainId: GraphChainId, 14 | ) { 15 | return await createAttestation(signer, chainId, disputeManagerAddress, receipt, '0') 16 | } 17 | 18 | export function encodeAttestation(attestation: Attestation): string { 19 | return encodeAttestationLib(attestation) 20 | } 21 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/network/actions/pause.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 2 | import { GraphNetworkContracts } from '../deployment/contracts/load' 3 | import { GraphNetworkAction } from './types' 4 | 5 | export const setPausedProtocol: GraphNetworkAction<{ paused: boolean }> = async ( 6 | contracts: GraphNetworkContracts, 7 | governorOrPauseGuardian: SignerWithAddress, 8 | args: { paused: boolean }, 9 | ): Promise => { 10 | const { paused } = args 11 | const { Controller } = contracts 12 | 13 | console.log(`\nSetting protocol paused to ${paused}...`) 14 | const tx = await Controller.connect(governorOrPauseGuardian).setPaused(paused) 15 | await tx.wait() 16 | } 17 | 18 | export const setPausedBridge: GraphNetworkAction<{ paused: boolean }> = async ( 19 | contracts: GraphNetworkContracts, 20 | governorOrPauseGuardian: SignerWithAddress, 21 | args: { paused: boolean }, 22 | ): Promise => { 23 | const { paused } = args 24 | const { GraphTokenGateway } = contracts 25 | 26 | console.log(`\nSetting bridge ${GraphTokenGateway.address} paused to ${paused}...`) 27 | const tx = await GraphTokenGateway.connect(governorOrPauseGuardian).setPaused(paused) 28 | await tx.wait() 29 | } 30 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/network/actions/types.ts: -------------------------------------------------------------------------------- 1 | import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 2 | import type { GraphNetworkContracts } from '../deployment/contracts/load' 3 | 4 | export type GraphNetworkAction = ( 5 | contracts: GraphNetworkContracts, 6 | signer: SignerWithAddress, 7 | args: A, 8 | ) => Promise 9 | -------------------------------------------------------------------------------- /packages/sdk/src/deployments/network/deployment/address-book.ts: -------------------------------------------------------------------------------- 1 | import { GraphNetworkContractName, isGraphNetworkContractName } from './contracts/list' 2 | import { GraphChainId, isGraphChainId } from '../../..' 3 | import { AddressBook } from '../../lib/address-book' 4 | 5 | import type { AddressBookJson } from '../../lib/types/address-book' 6 | 7 | export class GraphNetworkAddressBook extends AddressBook { 8 | assertChainId(chainId: string | number): asserts chainId is GraphChainId { 9 | if (!isGraphChainId(chainId)) { 10 | throw new Error(`ChainId not supported: ${chainId}`) 11 | } 12 | } 13 | 14 | // Asserts the provided object is a valid address book 15 | // Logs warnings for unsupported chain ids or invalid contract names 16 | // TODO: should we enforce json format here and throw instead of just logging? 17 | assertAddressBookJson( 18 | json: unknown, 19 | ): asserts json is AddressBookJson { 20 | this._assertAddressBookJson(json) 21 | 22 | // // Validate contract names 23 | const contractList = json[this.chainId] 24 | 25 | const contractNames = contractList ? Object.keys(contractList) : [] 26 | for (const contract of contractNames) { 27 | if (!isGraphNetworkContractName(contract)) { 28 | const message = `Detected invalid GraphNetworkContract in address book: ${contract}, for chainId ${this.chainId}` 29 | if (this.strictAssert) { 30 | throw new Error(message) 31 | } else { 32 | console.error(message) 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/helpers/argv.ts: -------------------------------------------------------------------------------- 1 | import { GraphRuntimeEnvironmentOptions } from '../types' 2 | 3 | export function getGREOptsFromArgv(): GraphRuntimeEnvironmentOptions { 4 | const argv = process.argv.slice(2) 5 | 6 | const getArgv: any = (index: number) => 7 | argv[index] && argv[index] !== 'undefined' ? argv[index] : undefined 8 | 9 | return { 10 | addressBook: getArgv(0), 11 | graphConfig: getArgv(1), 12 | l1GraphConfig: getArgv(2), 13 | l2GraphConfig: getArgv(3), 14 | disableSecureAccounts: getArgv(4) === 'true', 15 | fork: getArgv(5) === 'true', 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/helpers/error.ts: -------------------------------------------------------------------------------- 1 | import { HardhatPluginError } from 'hardhat/plugins' 2 | import { logError } from './logger' 3 | 4 | export class GREPluginError extends HardhatPluginError { 5 | constructor(message: string) { 6 | super('GraphRuntimeEnvironment', message) 7 | logError(message) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/helpers/logger.ts: -------------------------------------------------------------------------------- 1 | import debug from 'debug' 2 | 3 | const LOG_BASE = 'hardhat:gre' 4 | 5 | export const logDebug = debug(`${LOG_BASE}:debug`) 6 | export const logWarn = debug(`${LOG_BASE}:warn`) 7 | export const logError = debug(`${LOG_BASE}:error`) 8 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/helpers/utils.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | export function normalizePath(_path: string, graphPath?: string): string { 4 | if (!path.isAbsolute(_path) && graphPath !== undefined) { 5 | _path = path.join(graphPath, _path) 6 | } 7 | return _path 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/index.ts: -------------------------------------------------------------------------------- 1 | import { extendConfig, extendEnvironment } from 'hardhat/config' 2 | import { greExtendConfig, greExtendEnvironment } from './gre' 3 | 4 | // Plugin dependencies 5 | import 'hardhat-secure-accounts' 6 | 7 | // This import is needed to let the TypeScript compiler know that it should include your type 8 | // extensions in your npm package's types file. 9 | import './type-extensions' 10 | 11 | // ** Graph Runtime Environment (GRE) extensions for the HRE ** 12 | extendConfig(greExtendConfig) 13 | extendEnvironment(greExtendEnvironment) 14 | 15 | // Exports 16 | export * from './types' 17 | export { greTask as greTask } from './task' 18 | export { getGREOptsFromArgv } from './helpers/argv' 19 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config' 2 | import { ActionType, ConfigurableTaskDefinition } from 'hardhat/types/runtime' 3 | 4 | function grePrefix(text: string): string { 5 | return `[GRE] ${text}` 6 | } 7 | 8 | export function greTask( 9 | name: string, 10 | description?: string | undefined, 11 | action?: ActionType | undefined, 12 | ): ConfigurableTaskDefinition { 13 | return task(name, description, action) 14 | .addOptionalParam('addressBook', grePrefix('Path to the address book file.')) 15 | .addOptionalParam( 16 | 'graphConfig', 17 | grePrefix( 18 | 'Path to the graph config file for the network specified using --network. Lower priority than --l1GraphConfig and --l2GraphConfig.', 19 | ), 20 | ) 21 | .addOptionalParam( 22 | 'l1GraphConfig', 23 | grePrefix('Path to the graph config file for the L1 network.'), 24 | ) 25 | .addOptionalParam( 26 | 'l2GraphConfig', 27 | grePrefix('Path to the graph config file for the L2 network.'), 28 | ) 29 | .addFlag('disableSecureAccounts', grePrefix('Disable secure accounts plugin.')) 30 | .addFlag('enableTxLogging', grePrefix('Enable transaction logging.')) 31 | .addFlag('fork', grePrefix('Wether or not the network is a fork.')) 32 | } 33 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/addresses-hre.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/addresses-hre.json -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/addresses-opts.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/addresses-opts.json -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.arbitrum-goerli.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.arbitrum-goerli.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.arbitrum-hre.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.arbitrum-hre.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.arbitrum-opts.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.arbitrum-opts.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.goerli.yml: -------------------------------------------------------------------------------- 1 | general: 2 | arbitrator: &arbitrator "0xFD01aa87BeB04D0ac764FC298aCFd05FfC5439cD" # Arbitration Council 3 | governor: &governor "0xf1135bFF22512FF2A585b8d4489426CE660f204c" # Graph Council 4 | authority: &authority "0x52e498aE9B8A5eE2A5Cd26805F06A9f29A7F489F" # Authority that signs payment vouchers 5 | availabilityOracle: &availabilityOracle "0x14053D40ea2E81D3AB0739728a54ab84F21200F9" # Subgraph Availability Oracle 6 | pauseGuardian: &pauseGuardian "0x6855D551CaDe60754D145fb5eDCD90912D860262" # Protocol pause guardian 7 | allocationExchangeOwner: &allocationExchangeOwner "0xf1135bFF22512FF2A585b8d4489426CE660f204c" # Allocation Exchange owner 8 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.hre.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.hre.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.mainnet.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.mainnet.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.opts.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.opts.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/files/config/graph.opts2.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/sdk/src/gre/test/files/config/graph.opts2.yml -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/default-config/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | mainnet: { 4 | chainId: 1, 5 | url: `https://mainnet.infura.io/v3/123456`, 6 | }, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config-bad/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import '../../..' 2 | 3 | module.exports = { 4 | paths: { 5 | graph: '../../files', 6 | }, 7 | solidity: '0.8.9', 8 | defaultNetwork: 'hardhat', 9 | networks: { 10 | hardhat: { 11 | chainId: 1337, 12 | }, 13 | mainnet: { 14 | chainId: 1, 15 | graphConfig: 'config/graph.mainnet-does-not-exist.yml', 16 | url: `https://mainnet.infura.io/v3/123456`, 17 | }, 18 | 'arbitrum-one': { 19 | chainId: 42161, 20 | url: 'https://arb1.arbitrum.io/rpc', 21 | graphConfig: 'config/graph.arbitrum-does-not-exist.yml', 22 | }, 23 | goerli: { 24 | chainId: 5, 25 | url: `https://goerli.infura.io/v3/123456`, 26 | }, 27 | // 'arbitrum-goerli': { 28 | // chainId: 421613, 29 | // url: 'https://goerli-rollup.arbitrum.io/rpc', 30 | // }, 31 | // rinkeby: { 32 | // chainId: 4, 33 | // url: `https://goerli.infura.io/v3/123456`, 34 | // }, 35 | 'arbitrum-rinkeby': { 36 | chainId: 421611, 37 | url: `https://goerli.infura.io/v3/123456`, 38 | }, 39 | }, 40 | graph: { 41 | addressBook: 'addresses-does-not-exist.json', 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config-desambiguate/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import '../../..' 2 | 3 | module.exports = { 4 | paths: { 5 | graph: '../../files', 6 | }, 7 | solidity: '0.8.9', 8 | defaultNetwork: 'hardhat', 9 | networks: { 10 | hardhat: { 11 | chainId: 1337, 12 | }, 13 | localhost: { 14 | chainId: 1337, 15 | url: `http://127.0.0.1:8545`, 16 | }, 17 | localnitrol1: { 18 | chainId: 1337, 19 | url: `http://127.0.0.1:8545`, 20 | }, 21 | localnitrol2: { 22 | chainId: 412346, 23 | url: `http://127.0.0.1:8547`, 24 | }, 25 | mainnet: { 26 | chainId: 1, 27 | graphConfig: 'config/graph.mainnet.yml', 28 | url: `https://mainnet.infura.io/v3/123456`, 29 | }, 30 | 'arbitrum-one': { 31 | chainId: 42161, 32 | url: 'https://arb1.arbitrum.io/rpc', 33 | graphConfig: 'config/graph.arbitrum-goerli.yml', 34 | }, 35 | goerli: { 36 | chainId: 5, 37 | url: `https://goerli.infura.io/v3/123456`, 38 | graphConfig: 'config/graph.goerli.yml', 39 | }, 40 | 'arbitrum-goerli': { 41 | chainId: 421613, 42 | url: 'https://goerli-rollup.arbitrum.io/rpc', 43 | graphConfig: 'config/graph.arbitrum-goerli.yml', 44 | }, 45 | rinkeby: { 46 | chainId: 4, 47 | url: `https://goerli.infura.io/v3/123456`, 48 | }, 49 | 'arbitrum-rinkeby': { 50 | chainId: 421611, 51 | url: `https://goerli.infura.io/v3/123456`, 52 | }, 53 | }, 54 | graph: { 55 | addressBook: 'addresses-hre.json', 56 | l1GraphConfig: 'config/graph.hre.yml', 57 | l2GraphConfig: 'config/graph.arbitrum-hre.yml', 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config-full/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import '../../..' 2 | 3 | module.exports = { 4 | paths: { 5 | graph: '../../files', 6 | }, 7 | solidity: '0.8.9', 8 | defaultNetwork: 'hardhat', 9 | networks: { 10 | hardhat: { 11 | chainId: 1337, 12 | }, 13 | mainnet: { 14 | chainId: 1, 15 | graphConfig: 'config/graph.mainnet.yml', 16 | url: `https://mainnet.infura.io/v3/123456`, 17 | }, 18 | 'arbitrum-one': { 19 | chainId: 42161, 20 | url: 'https://arb1.arbitrum.io/rpc', 21 | graphConfig: 'config/graph.arbitrum-goerli.yml', 22 | }, 23 | goerli: { 24 | chainId: 5, 25 | url: `https://goerli.infura.io/v3/123456`, 26 | graphConfig: 'config/graph.goerli.yml', 27 | }, 28 | 'arbitrum-goerli': { 29 | chainId: 421613, 30 | url: 'https://goerli-rollup.arbitrum.io/rpc', 31 | graphConfig: 'config/graph.arbitrum-goerli.yml', 32 | }, 33 | rinkeby: { 34 | chainId: 4, 35 | url: `https://goerli.infura.io/v3/123456`, 36 | }, 37 | 'arbitrum-rinkeby': { 38 | chainId: 421611, 39 | url: `https://goerli.infura.io/v3/123456`, 40 | }, 41 | }, 42 | graph: { 43 | addressBook: 'addresses-hre.json', 44 | l1GraphConfig: 'config/graph.hre.yml', 45 | l2GraphConfig: 'config/graph.arbitrum-hre.yml', 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config/.accounts/test-account-l2.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "5baa8472c470a400f830e2458ddb97b13cc8eb32", 3 | "id": "ead5a876-efae-4cdf-aeab-ab81907427c8", 4 | "version": 3, 5 | "Crypto": { 6 | "cipher": "aes-128-ctr", 7 | "cipherparams": { "iv": "5e90eb61380cee63382bd8c935eea554" }, 8 | "ciphertext": "67800c67ab32b8baf2df4a697aa1108ee7f91b5a182ff2e29fa562009e1bbd9f", 9 | "kdf": "scrypt", 10 | "kdfparams": { 11 | "salt": "415db4971651654fb4b381f86525c273e4c7470a69307f7c83f71ec38aca7d12", 12 | "n": 131072, 13 | "dklen": 32, 14 | "p": 1, 15 | "r": 8 16 | }, 17 | "mac": "f5611372940c7da01e774aaf35046a5b3c4eec050d482b9f0912707ba645e681" 18 | }, 19 | "x-ethers": { 20 | "client": "ethers.js", 21 | "gethFilename": "UTC--2022-08-25T14-48-23.0Z--5baa8472c470a400f830e2458ddb97b13cc8eb32", 22 | "mnemonicCounter": "b84bf04ecd5d0ab111950ee4cf168d86", 23 | "mnemonicCiphertext": "672a53846059b4e8bae97747d684529a", 24 | "path": "m/44'/60'/0'/0/0", 25 | "locale": "en", 26 | "version": "0.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config/.accounts/test-account.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "c108fda1b5b2903751594298769efd4904b146bd", 3 | "id": "37ec99f7-8244-4982-b2d4-173c244784f3", 4 | "version": 3, 5 | "Crypto": { 6 | "cipher": "aes-128-ctr", 7 | "cipherparams": { "iv": "1eb9d55c0882a50e7988a09e674c2402" }, 8 | "ciphertext": "822fd907f44e48d15d500433200ac244b70487813982936a88c0830fa9cd66b6", 9 | "kdf": "scrypt", 10 | "kdfparams": { 11 | "salt": "f6d158afdf9a11d3353fbe736cbb769626c8428015603c6449ca1fa0b42e3c2e", 12 | "n": 131072, 13 | "dklen": 32, 14 | "p": 1, 15 | "r": 8 16 | }, 17 | "mac": "1af4526f4e62b6722226ee1c3a18d7f5dfff0d5b7862ca123989e7a464153f28" 18 | }, 19 | "x-ethers": { 20 | "client": "ethers.js", 21 | "gethFilename": "UTC--2022-08-24T12-27-39.0Z--c108fda1b5b2903751594298769efd4904b146bd", 22 | "mnemonicCounter": "3bd3b82c7148351fe0cdc005a631d445", 23 | "mnemonicCiphertext": "f2bc1c5598c60fe265bf7908344fde6d", 24 | "path": "m/44'/60'/0'/0/0", 25 | "locale": "en", 26 | "version": "0.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/fixture-projects/graph-config/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import '../../..' 2 | 3 | module.exports = { 4 | paths: { 5 | graph: '../../files', 6 | accounts: '.accounts', 7 | }, 8 | solidity: '0.8.9', 9 | defaultNetwork: 'hardhat', 10 | networks: { 11 | hardhat: { 12 | chainId: 1337, 13 | accounts: { 14 | mnemonic: 'pumpkin orient can short never warm truth legend cereal tourist craft skin', 15 | }, 16 | }, 17 | mainnet: { 18 | chainId: 1, 19 | graphConfig: 'config/graph.mainnet.yml', 20 | url: `https://mainnet.infura.io/v3/123456`, 21 | }, 22 | 'arbitrum-one': { 23 | chainId: 42161, 24 | url: 'https://arb1.arbitrum.io/rpc', 25 | }, 26 | goerli: { 27 | chainId: 5, 28 | url: `https://goerli.infura.io/v3/123456`, 29 | }, 30 | 'arbitrum-goerli': { 31 | chainId: 421613, 32 | url: 'https://goerli-rollup.arbitrum.io/rpc', 33 | }, 34 | localhost: { 35 | chainId: 1337, 36 | url: 'http://127.0.0.1:8545', 37 | }, 38 | 'arbitrum-rinkeby': { 39 | chainId: 421611, 40 | url: 'http://127.0.0.1:8545', 41 | }, 42 | }, 43 | graph: { 44 | addressBook: 'addresses-hre.json', 45 | l1GraphConfig: 'config/graph.goerli.yml', 46 | l2GraphConfig: 'config/graph.arbitrum-goerli.yml', 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/test/helpers.ts: -------------------------------------------------------------------------------- 1 | import { resetHardhatContext } from 'hardhat/plugins-testing' 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types' 3 | import path from 'path' 4 | 5 | declare module 'mocha' { 6 | interface Context { 7 | hre: HardhatRuntimeEnvironment 8 | } 9 | } 10 | 11 | export function useEnvironment(fixtureProjectName: string, network?: string): void { 12 | beforeEach('Loading hardhat environment', function () { 13 | process.chdir(path.join(__dirname, 'fixture-projects', fixtureProjectName)) 14 | 15 | if (network !== undefined) { 16 | process.env.HARDHAT_NETWORK = network 17 | } 18 | this.hre = require('hardhat') 19 | }) 20 | 21 | afterEach('Resetting hardhat', function () { 22 | resetHardhatContext() 23 | delete process.env.HARDHAT_NETWORK 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/type-extensions.ts: -------------------------------------------------------------------------------- 1 | // To extend one of Hardhat's types, you need to import the module where it has been defined, and redeclare it. 2 | import 'hardhat/types/config' 3 | import 'hardhat/types/runtime' 4 | 5 | import type { GraphRuntimeEnvironment, GraphRuntimeEnvironmentOptions } from './types' 6 | 7 | declare module 'hardhat/types/runtime' { 8 | export interface HardhatRuntimeEnvironment { 9 | graph: (opts?: GraphRuntimeEnvironmentOptions) => GraphRuntimeEnvironment 10 | } 11 | } 12 | 13 | declare module 'hardhat/types/config' { 14 | export interface HardhatConfig { 15 | graph: Omit 16 | } 17 | 18 | export interface HardhatUserConfig { 19 | graph: Omit 20 | } 21 | 22 | export interface HardhatNetworkConfig { 23 | graphConfig?: string 24 | addressBook?: string 25 | } 26 | 27 | export interface HardhatNetworkUserConfig { 28 | graphConfig?: string 29 | addressBook?: string 30 | } 31 | 32 | export interface HttpNetworkConfig { 33 | graphConfig?: string 34 | addressBook?: string 35 | } 36 | 37 | export interface HttpNetworkUserConfig { 38 | graphConfig?: string 39 | addressBook?: string 40 | } 41 | 42 | export interface ProjectPathsConfig { 43 | graph?: string 44 | } 45 | 46 | export interface ProjectPathsUserConfig { 47 | graph?: string 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/sdk/src/gre/types.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 2 | import { GraphNetworkAddressBook, GraphNetworkContracts } from '..' 3 | 4 | import { EthersProviderWrapper } from '@nomiclabs/hardhat-ethers/internal/ethers-provider-wrapper' 5 | import { Wallet } from 'ethers' 6 | 7 | export interface GraphRuntimeEnvironmentOptions { 8 | addressBook?: string 9 | l1GraphConfig?: string 10 | l2GraphConfig?: string 11 | graphConfig?: string 12 | enableTxLogging?: boolean 13 | disableSecureAccounts?: boolean 14 | fork?: boolean 15 | 16 | // These are mostly for testing purposes 17 | l1AccountName?: string 18 | l2AccountName?: string 19 | l1AccountPassword?: string 20 | l2AccountPassword?: string 21 | } 22 | 23 | export type AccountNames = 24 | | 'arbitrator' 25 | | 'governor' 26 | | 'authority' 27 | | 'availabilityOracle' 28 | | 'pauseGuardian' 29 | | 'allocationExchangeOwner' 30 | 31 | export type NamedAccounts = { 32 | [name in AccountNames]: SignerWithAddress 33 | } 34 | 35 | export interface GraphNetworkEnvironment { 36 | chainId: number 37 | provider: EthersProviderWrapper 38 | contracts: GraphNetworkContracts 39 | graphConfig: any 40 | addressBook: GraphNetworkAddressBook 41 | getNamedAccounts: () => Promise 42 | getTestAccounts: () => Promise 43 | getAllAccounts: () => Promise 44 | getDeployer: () => Promise 45 | getWallets: () => Promise 46 | getWallet: (address: string) => Promise 47 | } 48 | 49 | export interface GraphRuntimeEnvironment extends GraphNetworkEnvironment { 50 | l1: GraphNetworkEnvironment | null 51 | l2: GraphNetworkEnvironment | null 52 | } 53 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/balance.ts: -------------------------------------------------------------------------------- 1 | import { setBalance as hardhatSetBalance } from '@nomicfoundation/hardhat-network-helpers' 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 3 | 4 | import type { BigNumber } from 'ethers' 5 | 6 | export async function setBalance( 7 | address: string, 8 | balance: BigNumber | number, 9 | funder?: SignerWithAddress, 10 | ) { 11 | try { 12 | await hardhatSetBalance(address, balance) 13 | } catch (error) { 14 | if (funder === undefined) throw error 15 | await funder.sendTransaction({ to: address, value: balance }) 16 | } 17 | } 18 | 19 | export async function setBalances( 20 | args: { address: string; balance: BigNumber }[], 21 | funder?: SignerWithAddress, 22 | ) { 23 | for (let i = 0; i < args.length; i++) { 24 | await setBalance(args[i].address, args[i].balance, funder) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/code.ts: -------------------------------------------------------------------------------- 1 | import { setCode as hardhatSetCode } from '@nomicfoundation/hardhat-network-helpers' 2 | 3 | export async function setCode(address: string, code: string): Promise { 4 | return hardhatSetCode(address, code) 5 | } 6 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/epoch.ts: -------------------------------------------------------------------------------- 1 | import { mine } from './mine' 2 | import type { EpochManager } from '@graphprotocol/contracts' 3 | 4 | export type PartialEpochManager = Pick 5 | 6 | export async function mineEpoch(epochManager: PartialEpochManager, epochs?: number): Promise { 7 | epochs = epochs ?? 1 8 | for (let i = 0; i < epochs; i++) { 9 | epochManager 10 | await _mineEpoch(epochManager) 11 | } 12 | } 13 | 14 | async function _mineEpoch(epochManager: PartialEpochManager): Promise { 15 | const blocksSinceEpoch = await epochManager.currentEpochBlockSinceStart() 16 | const epochLen = await epochManager.epochLength() 17 | return mine(epochLen.sub(blocksSinceEpoch)) 18 | } 19 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/impersonate.ts: -------------------------------------------------------------------------------- 1 | import { impersonateAccount as hardhatImpersonateAccount } from '@nomicfoundation/hardhat-network-helpers' 2 | import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 3 | 4 | export async function impersonateAccount(address: string): Promise { 5 | const hre = await import('hardhat') 6 | await hardhatImpersonateAccount(address) 7 | 8 | // This allows the dynamic import to work on both ts and js 9 | const ethers = hre.ethers ?? hre.default.ethers 10 | return ethers.getSigner(address) 11 | } 12 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './arbitrum' 2 | export * from './balance' 3 | export * from './code' 4 | export * from './epoch' 5 | export * from './time' 6 | export * from './impersonate' 7 | export * from './mine' 8 | export * from './snapshot' 9 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/mine.ts: -------------------------------------------------------------------------------- 1 | import { 2 | mine as hardhatMine, 3 | mineUpTo as hardhatMineUpTo, 4 | } from '@nomicfoundation/hardhat-network-helpers' 5 | 6 | import type { BigNumber } from 'ethers' 7 | 8 | export async function mine( 9 | blocks?: string | number | BigNumber, 10 | interval?: string | number | BigNumber, 11 | ): Promise { 12 | return hardhatMine(blocks, { interval }) 13 | } 14 | 15 | export async function mineUpTo(blockNumber: string | number | BigNumber): Promise { 16 | return hardhatMineUpTo(blockNumber) 17 | } 18 | 19 | export async function setAutoMine(autoMine: boolean): Promise { 20 | const hre = await import('hardhat') 21 | 22 | // This allows the dynamic import to work on both ts and js 23 | const network = hre.network ?? hre.default.network 24 | return network.provider.send('evm_setAutomine', [autoMine]) 25 | } 26 | 27 | export async function setIntervalMining(interval: number): Promise { 28 | const hre = await import('hardhat') 29 | 30 | // This allows the dynamic import to work on both ts and js 31 | const network = hre.network ?? hre.default.network 32 | return network.provider.send('evm_setIntervalMining', [interval]) 33 | } 34 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/snapshot.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SnapshotRestorer, 3 | takeSnapshot as hardhatTakeSnapshot, 4 | } from '@nomicfoundation/hardhat-network-helpers' 5 | 6 | export async function takeSnapshot(): Promise { 7 | return hardhatTakeSnapshot() 8 | } 9 | 10 | export async function restoreSnapshot(snapshot: SnapshotRestorer): Promise { 11 | return snapshot.restore() 12 | } 13 | 14 | export type { SnapshotRestorer } from '@nomicfoundation/hardhat-network-helpers' 15 | -------------------------------------------------------------------------------- /packages/sdk/src/helpers/time.ts: -------------------------------------------------------------------------------- 1 | import { time } from '@nomicfoundation/hardhat-network-helpers' 2 | 3 | export async function latestBlock(): Promise { 4 | return time.latestBlock() 5 | } 6 | -------------------------------------------------------------------------------- /packages/sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chain' 2 | export * from './deployments' 3 | export * as helpers from './helpers' 4 | export * from './utils' 5 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/abi.ts: -------------------------------------------------------------------------------- 1 | export function mergeABIs(abi1: any[], abi2: any[]) { 2 | for (const item of abi2) { 3 | if (abi1.find((v) => v.name === item.name) === undefined) { 4 | abi1.push(item) 5 | } 6 | } 7 | return abi1 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/address.ts: -------------------------------------------------------------------------------- 1 | import { getAddress } from 'ethers/lib/utils' 2 | import { randomHexBytes } from './bytes' 3 | 4 | export const randomAddress = (): string => getAddress(randomHexBytes(20)) 5 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/allocation.ts: -------------------------------------------------------------------------------- 1 | import { utils, Wallet } from 'ethers' 2 | import type { Signer } from 'ethers' 3 | 4 | export enum AllocationState { 5 | Null, 6 | Active, 7 | Closed, 8 | Finalized, 9 | Claimed, 10 | } 11 | 12 | export interface ChannelKey { 13 | privKey: string 14 | pubKey: string 15 | address: string 16 | wallet: Signer 17 | generateProof: (address: string) => Promise 18 | } 19 | 20 | export const deriveChannelKey = (): ChannelKey => { 21 | const w = Wallet.createRandom() 22 | return { 23 | privKey: w.privateKey, 24 | pubKey: w.publicKey, 25 | address: w.address, 26 | wallet: w, 27 | generateProof: (indexerAddress: string): Promise => { 28 | const messageHash = utils.solidityKeccak256( 29 | ['address', 'address'], 30 | [indexerAddress, w.address], 31 | ) 32 | const messageHashBytes = utils.arrayify(messageHash) 33 | return w.signMessage(messageHashBytes) 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/arbitrum/address.ts: -------------------------------------------------------------------------------- 1 | import { hexZeroPad } from 'ethers/lib/utils' 2 | import { toBN } from '../units' 3 | 4 | // Adapted from: 5 | // https://github.com/livepeer/arbitrum-lpt-bridge/blob/e1a81edda3594e434dbcaa4f1ebc95b7e67ecf2a/utils/arbitrum/messaging.ts#L118 6 | export const applyL1ToL2Alias = (l1Address: string): string => { 7 | const offset = toBN('0x1111000000000000000000000000000000001111') 8 | const l1AddressAsNumber = toBN(l1Address) 9 | const l2AddressAsNumber = l1AddressAsNumber.add(offset) 10 | 11 | const mask = toBN(2).pow(160) 12 | return hexZeroPad(l2AddressAsNumber.mod(mask).toHexString(), 20) 13 | } 14 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/arbitrum/index.ts: -------------------------------------------------------------------------------- 1 | export { applyL1ToL2Alias } from './address' 2 | export { estimateRetryableTxGas, type L2GasParams } from './gas' 3 | export * from './message' 4 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/assertions.ts: -------------------------------------------------------------------------------- 1 | import { AssertionError } from 'assert' 2 | 3 | export function assertObject( 4 | value: unknown, 5 | errorMessage?: string, 6 | ): asserts value is Record { 7 | if (typeof value !== 'object' || value == null) 8 | throw new AssertionError({ 9 | message: errorMessage ?? 'Not an object', 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/bytes.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | import { hexlify, randomBytes } from 'ethers/lib/utils' 3 | 4 | export const randomHexBytes = (n = 32): string => hexlify(randomBytes(n)) 5 | 6 | export const base58ToHex = (base58: string): string => { 7 | return ethers.utils.hexlify(ethers.utils.base58.decode(base58)) 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/eip712.ts: -------------------------------------------------------------------------------- 1 | import { eip712 } from '@graphprotocol/common-ts/dist/attestations' 2 | import { BigNumber, BytesLike, Signature } from 'ethers' 3 | import { SigningKey, keccak256 } from 'ethers/lib/utils' 4 | 5 | export interface Permit { 6 | owner: string 7 | spender: string 8 | value: BigNumber 9 | nonce: BigNumber 10 | deadline: BigNumber 11 | } 12 | 13 | const PERMIT_TYPE_HASH = eip712.typeHash( 14 | 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)', 15 | ) 16 | 17 | export function signPermit( 18 | signer: BytesLike, 19 | chainId: number, 20 | contractAddress: string, 21 | permit: Permit, 22 | salt: string, 23 | ): Signature { 24 | const domainSeparator = eip712.domainSeparator({ 25 | name: 'Graph Token', 26 | version: '0', 27 | chainId, 28 | verifyingContract: contractAddress, 29 | salt: salt, 30 | }) 31 | const hashEncodedPermit = hashEncodePermit(permit) 32 | const message = eip712.encode(domainSeparator, hashEncodedPermit) 33 | const messageHash = keccak256(message) 34 | const signingKey = new SigningKey(signer) 35 | return signingKey.signDigest(messageHash) 36 | } 37 | 38 | function hashEncodePermit(permit: Permit) { 39 | return eip712.hashStruct( 40 | PERMIT_TYPE_HASH, 41 | ['address', 'address', 'uint256', 'uint256', 'uint256'], 42 | [permit.owner, permit.spender, permit.value, permit.nonce, permit.deadline], 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | import { keccak256 } from 'ethers/lib/utils' 2 | 3 | export const hashHexString = (input: string): string => keccak256(`0x${input.replace(/^0x/, '')}`) 4 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './address' 2 | export * from './arbitrum' 3 | export * from './bytes' 4 | export * from './hash' 5 | export * from './subgraph' 6 | export * from './allocation' 7 | export * from './units' 8 | export * from './eip712' 9 | export * from './prompt' 10 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/nonce.ts: -------------------------------------------------------------------------------- 1 | import { NonceManager } from '@ethersproject/experimental' 2 | 3 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' 4 | import type { providers } from 'ethers' 5 | 6 | export class NonceManagerWithAddress extends NonceManager { 7 | public address: string 8 | public signerWithAddress: SignerWithAddress 9 | 10 | constructor(signer: SignerWithAddress) { 11 | super(signer) 12 | this.address = signer.address 13 | this.signerWithAddress = signer 14 | } 15 | 16 | connect(provider: providers.Provider): NonceManager { 17 | return new NonceManagerWithAddress(this.signerWithAddress.connect(provider)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/prompt.ts: -------------------------------------------------------------------------------- 1 | import inquirer from 'inquirer' 2 | 3 | export const confirm = async (message: string, skip: boolean): Promise => { 4 | if (skip) return true 5 | const res = await inquirer.prompt({ 6 | name: 'confirm', 7 | type: 'confirm', 8 | message, 9 | }) 10 | if (!res.confirm) { 11 | console.info('Cancelled') 12 | return false 13 | } 14 | return true 15 | } 16 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/subgraph.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, ethers } from 'ethers' 2 | import { solidityKeccak256 } from 'ethers/lib/utils' 3 | import { base58ToHex, randomHexBytes } from './bytes' 4 | 5 | export interface PublishSubgraph { 6 | subgraphDeploymentID: string 7 | versionMetadata: string 8 | subgraphMetadata: string 9 | } 10 | 11 | export interface Subgraph { 12 | vSignal: BigNumber 13 | nSignal: BigNumber 14 | subgraphDeploymentID: string 15 | reserveRatioDeprecated: number 16 | disabled: boolean 17 | withdrawableGRT: BigNumber 18 | id?: string 19 | } 20 | 21 | export const buildSubgraphId = async ( 22 | account: string, 23 | seqId: number | BigNumber, 24 | chainId: number | BigNumber, 25 | ): Promise => { 26 | return solidityKeccak256(['address', 'uint256', 'uint256'], [account, seqId, chainId]) 27 | } 28 | 29 | export const buildLegacySubgraphId = (account: string, seqID: BigNumber): string => 30 | solidityKeccak256(['address', 'uint256'], [account, seqID]) 31 | 32 | export const buildSubgraph = (): PublishSubgraph => { 33 | return { 34 | subgraphDeploymentID: randomHexBytes(), 35 | versionMetadata: randomHexBytes(), 36 | subgraphMetadata: randomHexBytes(), 37 | } 38 | } 39 | 40 | export const subgraphIdToHex = (id: string): string => { 41 | id = id.startsWith('Qm') ? id : `Qm${id}` 42 | return `0x${base58ToHex(id).slice(6)}` 43 | } 44 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/time.ts: -------------------------------------------------------------------------------- 1 | export const wait = (ms: number): Promise => { 2 | return new Promise((res) => setTimeout(res, ms)) 3 | } 4 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/type-guard.ts: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/58278652/generic-enum-type-guard 2 | export function isSomeEnum>( 3 | e: T, 4 | ): (token: unknown) => token is T[keyof T] { 5 | const keys = Object.keys(e).filter((k) => { 6 | return !/^\d/.test(k) 7 | }) 8 | const values = keys.map((k) => { 9 | return (e as any)[k] 10 | }) 11 | return (token: unknown): token is T[keyof T] => { 12 | return values.includes(token) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/units.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from 'ethers' 2 | import { formatUnits, parseUnits } from 'ethers/lib/utils' 3 | 4 | export const toBN = (value: string | number): BigNumber => BigNumber.from(value) 5 | export const toGRT = (value: string | number): BigNumber => { 6 | return parseUnits(typeof value === 'number' ? value.toString() : value, '18') 7 | } 8 | export const formatGRT = (value: BigNumber): string => formatUnits(value, '18') 9 | -------------------------------------------------------------------------------- /packages/token-distribution/.env.sample: -------------------------------------------------------------------------------- 1 | MNEMONIC= 2 | ETHERSCAN_API_KEY= 3 | INFURA_KEY= 4 | STUDIO_API_KEY= 5 | -------------------------------------------------------------------------------- /packages/token-distribution/.graphclientrc.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | - name: graph-network 3 | handler: 4 | graphql: 5 | endpoint: https://gateway.thegraph.com/api/${STUDIO_API_KEY}/subgraphs/id/9Co7EQe5PgW3ugCUJrJgRv4u9zdEuDJf8NvMWftNsBH8 6 | retry: 5 7 | 8 | - name: token-distribution 9 | handler: 10 | graphql: 11 | endpoint: https://gateway.thegraph.com/api/${STUDIO_API_KEY}/subgraphs/id/ChfAJn6jQEBjVqtdUiThfG6sWy2Sr5XQPNucE9DkgXSN 12 | retry: 5 13 | transforms: 14 | - autoPagination: 15 | validateSchema: true 16 | 17 | documents: 18 | - ops/queries/account.graphql 19 | - ops/queries/curators.graphql 20 | - ops/queries/network.graphql 21 | - ops/queries/tokenLockWallets.graphql 22 | -------------------------------------------------------------------------------- /packages/token-distribution/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.markdownlint.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/token-distribution/.openzeppelin/unknown-42161.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x69E5E6aae945d342d6FA17D112C137D18E52C4Af", 5 | "txHash": "0x00dcd23252a58b8304af1019f0d34dfefee1199c4b809acbc382d13615aee939" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0x23C9c8575E6bA0349a497b6D0E8F0b9239e68028", 10 | "txHash": "0xecb5b61a0d6fbca8f01174fea87d34172d4321650ba0566b0a9c87c7eca8df73", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "3dff628cbc1a793190dc5ae0bc979ad427a9a98001209a3664d22dafc301b9b1": { 16 | "address": "0x440e07acE09d848a581077c6DC8D7fb60FD8af62", 17 | "txHash": "0x19f4d4f2701765d612f8ec4d7703a3d84761c4d81f3822addea9ba7ed023e0b3", 18 | "layout": { 19 | "solcVersion": "0.7.3", 20 | "storage": [], 21 | "types": {} 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/token-distribution/.openzeppelin/unknown-421613.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0x5de859Bfd66BC330950c7dbf77F7F8fE519a1834", 5 | "txHash": "0xbc443c4f31a36a6ff2cb5a8f39d9debd530626f9f51a9acccf28db6cfb6e94e0" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xc1A9C2E76171e64Cd5669B3E89D9A25a6b0FAfB7", 10 | "txHash": "0x4c0fdb3290d0e247de1d0863bc2a7b13ea9414a86e5bfe94f1e2eba7c5c47f70", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "f6ef37a54af859f9b6df6f1932063a6236e85e4e6ef0d8873a358db6ba412cb5": { 16 | "address": "0xDc95A3418B4869c09572141Db70344434C8Bd9a8", 17 | "txHash": "0x4b3258ad891966098856994fb4b6fde4a156d275d3ad813daa4930b9fbcf7861", 18 | "layout": { 19 | "solcVersion": "0.7.3", 20 | "storage": [], 21 | "types": {} 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/token-distribution/.openzeppelin/unknown-421614.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "admin": { 4 | "address": "0xaf06340Afd383c81C0F025806f93e613Bf6229b2", 5 | "txHash": "0x9cae0d327af86d32826d828ce26eb50c3d7c1138a6591ceaebb2de5accef1fe5" 6 | }, 7 | "proxies": [ 8 | { 9 | "address": "0xe21cd62E1E0CD68476C47F518980226C0a05fB19", 10 | "txHash": "0x4785cb6bfeae00d727ed1199ad2724772507d6631135c73797069382a58af7d3", 11 | "kind": "transparent" 12 | } 13 | ], 14 | "impls": { 15 | "9473208ed72647e49559194b7e906bf5eeb9ed0daf880eefb020b9493100d856": { 16 | "address": "0x435F557d1fa367CAF33B567589F22a911Be28957", 17 | "txHash": "0x321a11019d5a3d8fbdf1ba435b4a7a9c1961f3a6178c8deb2aaaeaeae7515775", 18 | "layout": { 19 | "solcVersion": "0.7.3", 20 | "storage": [], 21 | "types": {} 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/token-distribution/.solcover.js: -------------------------------------------------------------------------------- 1 | const skipFiles = [''] 2 | 3 | module.exports = { 4 | providerOptions: { 5 | mnemonic: 'myth like bonus scare over problem client lizard pioneer submit female collect', 6 | network_id: 1337, 7 | }, 8 | skipFiles, 9 | istanbulFolder: './reports/coverage', 10 | } 11 | -------------------------------------------------------------------------------- /packages/token-distribution/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 The Graph Foundation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/token-distribution/audits/2020-11-graph-token-distribution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/token-distribution/audits/2020-11-graph-token-distribution.pdf -------------------------------------------------------------------------------- /packages/token-distribution/contracts/GraphTokenLockSimple.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.3; 4 | 5 | import "./GraphTokenLock.sol"; 6 | 7 | /** 8 | * @title GraphTokenLockSimple 9 | * @notice This contract is the concrete simple implementation built on top of the base 10 | * GraphTokenLock functionality for use when we only need the token lock schedule 11 | * features but no interaction with the network. 12 | * 13 | * This contract is designed to be deployed without the use of a TokenManager. 14 | */ 15 | contract GraphTokenLockSimple is GraphTokenLock { 16 | // Constructor 17 | constructor() { 18 | OwnableInitializable._initialize(msg.sender); 19 | } 20 | 21 | // Initializer 22 | function initialize( 23 | address _owner, 24 | address _beneficiary, 25 | address _token, 26 | uint256 _managedAmount, 27 | uint256 _startTime, 28 | uint256 _endTime, 29 | uint256 _periods, 30 | uint256 _releaseStartTime, 31 | uint256 _vestingCliffTime, 32 | Revocability _revocable 33 | ) external onlyOwner { 34 | _initialize( 35 | _owner, 36 | _beneficiary, 37 | _token, 38 | _managedAmount, 39 | _startTime, 40 | _endTime, 41 | _periods, 42 | _releaseStartTime, 43 | _vestingCliffTime, 44 | _revocable 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/token-distribution/contracts/ICallhookReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | // Copied from graphprotocol/contracts, changed solidity version to 0.7.3 4 | 5 | /** 6 | * @title Interface for contracts that can receive callhooks through the Arbitrum GRT bridge 7 | * @dev Any contract that can receive a callhook on L2, sent through the bridge from L1, must 8 | * be allowlisted by the governor, but also implement this interface that contains 9 | * the function that will actually be called by the L2GraphTokenGateway. 10 | */ 11 | pragma solidity ^0.7.3; 12 | 13 | interface ICallhookReceiver { 14 | /** 15 | * @notice Receive tokens with a callhook from the bridge 16 | * @param _from Token sender in L1 17 | * @param _amount Amount of tokens that were transferred 18 | * @param _data ABI-encoded callhook data 19 | */ 20 | function onTokenTransfer(address _from, uint256 _amount, bytes calldata _data) external; 21 | } 22 | -------------------------------------------------------------------------------- /packages/token-distribution/contracts/IGraphTokenLock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.3; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | 8 | interface IGraphTokenLock { 9 | enum Revocability { 10 | NotSet, 11 | Enabled, 12 | Disabled 13 | } 14 | 15 | // -- Balances -- 16 | 17 | function currentBalance() external view returns (uint256); 18 | 19 | // -- Time & Periods -- 20 | 21 | function currentTime() external view returns (uint256); 22 | 23 | function duration() external view returns (uint256); 24 | 25 | function sinceStartTime() external view returns (uint256); 26 | 27 | function amountPerPeriod() external view returns (uint256); 28 | 29 | function periodDuration() external view returns (uint256); 30 | 31 | function currentPeriod() external view returns (uint256); 32 | 33 | function passedPeriods() external view returns (uint256); 34 | 35 | // -- Locking & Release Schedule -- 36 | 37 | function availableAmount() external view returns (uint256); 38 | 39 | function vestedAmount() external view returns (uint256); 40 | 41 | function releasableAmount() external view returns (uint256); 42 | 43 | function totalOutstandingAmount() external view returns (uint256); 44 | 45 | function surplusAmount() external view returns (uint256); 46 | 47 | // -- Value Transfer -- 48 | 49 | function release() external; 50 | 51 | function withdrawSurplus(uint256 _amount) external; 52 | 53 | function revoke() external; 54 | } 55 | -------------------------------------------------------------------------------- /packages/token-distribution/contracts/MathUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.3; 4 | 5 | library MathUtils { 6 | function min(uint256 a, uint256 b) internal pure returns (uint256) { 7 | return a < b ? a : b; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/token-distribution/contracts/tests/GraphTokenMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.3; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | 8 | /** 9 | * @title Graph Token Mock contract. 10 | * @dev Used for testing purposes, DO NOT USE IN PRODUCTION 11 | */ 12 | contract GraphTokenMock is Ownable, ERC20 { 13 | /** 14 | * @notice Contract Constructor. 15 | * @param _initialSupply Initial supply 16 | * @param _mintTo Address to whitch to mint the initial supply 17 | */ 18 | constructor(uint256 _initialSupply, address _mintTo) ERC20("Graph Token Mock", "GRT-Mock") { 19 | // Deploy to mint address 20 | _mint(_mintTo, _initialSupply); 21 | } 22 | 23 | /** 24 | * @notice Mint tokens to an address from the bridge. 25 | * (The real one has an onlyGateway modifier) 26 | * @param _to Address to mint tokens to 27 | * @param _amount Amount of tokens to mint 28 | */ 29 | function bridgeMint(address _to, uint256 _amount) external { 30 | _mint(_to, _amount); 31 | } 32 | 33 | /** 34 | * @notice Burn tokens from an address from the bridge. 35 | * (The real one has an onlyGateway modifier) 36 | * @param _from Address to burn tokens from 37 | * @param _amount Amount of tokens to burn 38 | */ 39 | function bridgeBurn(address _from, uint256 _amount) external { 40 | _burn(_from, _amount); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/token-distribution/contracts/tests/arbitrum/IMessageProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | /* 4 | * Copyright 2021, Offchain Labs, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Originally copied from: 19 | * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth 20 | * 21 | * MODIFIED from Offchain Labs' implementation: 22 | * - Changed solidity version to 0.7.3 (pablo@edgeandnode.com) 23 | * 24 | */ 25 | 26 | pragma solidity ^0.7.3; 27 | 28 | interface IMessageProvider { 29 | event InboxMessageDelivered(uint256 indexed messageNum, bytes data); 30 | 31 | event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); 32 | } 33 | -------------------------------------------------------------------------------- /packages/token-distribution/deploy/1_test.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import consola from 'consola' 3 | 4 | import { HardhatRuntimeEnvironment } from 'hardhat/types' 5 | import { DeployFunction, DeployOptions } from 'hardhat-deploy/types' 6 | 7 | const { parseEther } = utils 8 | 9 | const logger = consola.create({}) 10 | 11 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 12 | const deploy = (name: string, options: DeployOptions) => hre.deployments.deploy(name, options) 13 | const { deployer } = await hre.getNamedAccounts() 14 | 15 | // -- Fake Graph Token -- 16 | 17 | logger.info('Deploying GraphTokenMock...') 18 | 19 | await deploy('GraphTokenMock', { 20 | from: deployer, 21 | args: [ 22 | parseEther('10000000000'), // 10B 23 | deployer, 24 | ], 25 | log: true, 26 | }) 27 | } 28 | 29 | func.skip = (hre: HardhatRuntimeEnvironment) => Promise.resolve(hre.network.name === 'mainnet') 30 | func.tags = ['test'] 31 | 32 | export default func 33 | -------------------------------------------------------------------------------- /packages/token-distribution/deploy/3_l2_wallet.ts: -------------------------------------------------------------------------------- 1 | import consola from 'consola' 2 | import '@nomiclabs/hardhat-ethers' 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types' 4 | import { DeployFunction, DeployOptions } from 'hardhat-deploy/types' 5 | 6 | import { getDeploymentName } from './lib/utils' 7 | 8 | const logger = consola.create({}) 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const deploy = (name: string, options: DeployOptions) => hre.deployments.deploy(name, options) 12 | const { deployer } = await hre.getNamedAccounts() 13 | 14 | // Deploy the master copy of GraphTokenLockWallet 15 | logger.info('Deploying L2GraphTokenLockWallet master copy...') 16 | const masterCopySaveName = await getDeploymentName('L2GraphTokenLockWallet') 17 | await deploy(masterCopySaveName, { 18 | from: deployer, 19 | log: true, 20 | contract: 'L2GraphTokenLockWallet', 21 | }) 22 | } 23 | 24 | func.tags = ['l2-wallet', 'l2'] 25 | 26 | export default func 27 | -------------------------------------------------------------------------------- /packages/token-distribution/deploy/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { Consola } from 'consola' 2 | import inquirer from 'inquirer' 3 | import { utils } from 'ethers' 4 | 5 | import '@nomiclabs/hardhat-ethers' 6 | 7 | const { getAddress } = utils 8 | 9 | export const askConfirm = async (message: string) => { 10 | const res = await inquirer.prompt({ 11 | name: 'confirm', 12 | type: 'confirm', 13 | message, 14 | }) 15 | return res.confirm ? res.confirm as boolean : false 16 | } 17 | 18 | export const promptContractAddress = async (name: string, logger: Consola): Promise => { 19 | const res1 = await inquirer.prompt({ 20 | name: 'contract', 21 | type: 'input', 22 | message: `What is the ${name} address?`, 23 | }) 24 | 25 | try { 26 | return getAddress(res1.contract) 27 | } catch (err) { 28 | logger.error(err) 29 | return null 30 | } 31 | } 32 | 33 | export const getDeploymentName = async (defaultName: string): Promise => { 34 | const res = await inquirer.prompt({ 35 | name: 'deployment-name', 36 | type: 'input', 37 | default: defaultName, 38 | message: 'Save deployment as?', 39 | }) 40 | return res['deployment-name'] as string 41 | } 42 | -------------------------------------------------------------------------------- /packages/token-distribution/deployments/arbitrum-goerli/.chainId: -------------------------------------------------------------------------------- 1 | 421613 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/arbitrum-one/.chainId: -------------------------------------------------------------------------------- 1 | 42161 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/arbitrum-sepolia/.chainId: -------------------------------------------------------------------------------- 1 | 421614 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/goerli/.chainId: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/mainnet/.chainId: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/rinkeby/.chainId: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /packages/token-distribution/deployments/sepolia/.chainId: -------------------------------------------------------------------------------- 1 | 11155111 -------------------------------------------------------------------------------- /packages/token-distribution/ops/deploy-data.csv: -------------------------------------------------------------------------------- 1 | beneficiary,managedAmount,startTime,endTime,periods,revocable,releaseStartTime,vestingCliffTime 2 | 0xCF143e9dd5D64dE5ef096b291BAc195968A06D0d,250000.00,1627776000,1754006400,48,1,1659312000,0 3 | 0x525ee071454cf9b6d750720bce8d8697ef82f02f,125000.00,1682899200,1777593600,36,1,1714435200,0 4 | 0xBe243A5907071185d1bAeBa85C9E426DA797e4dD,909090.91,1696809600,1823040000,48,1,0,0 5 | 0xD8068FEc14b3dd0223E21acfe978906556dAba99,500000.00,1697414400,1823644800,48,1,1728950400,0 -------------------------------------------------------------------------------- /packages/token-distribution/ops/queries/account.graphql: -------------------------------------------------------------------------------- 1 | query GraphAccount($accountId: ID!, $blockNumber: Int) { 2 | graphAccount(id: $accountId, block: { number: $blockNumber }) { 3 | id 4 | indexer { 5 | stakedTokens 6 | } 7 | curator { 8 | totalSignalledTokens 9 | totalUnsignalledTokens 10 | } 11 | delegator { 12 | totalStakedTokens 13 | totalUnstakedTokens 14 | totalRealizedRewards 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/token-distribution/ops/queries/curators.graphql: -------------------------------------------------------------------------------- 1 | query CuratorWallets($blockNumber: Int, $first: Int) { 2 | tokenLockWallets( 3 | block: { number: $blockNumber } 4 | where: { periods: 16, startTime: 1608224400, endTime: 1734454800, revocable: Disabled } 5 | first: $first 6 | orderBy: blockNumberCreated 7 | ) { 8 | id 9 | beneficiary 10 | managedAmount 11 | periods 12 | startTime 13 | endTime 14 | revocable 15 | releaseStartTime 16 | vestingCliffTime 17 | initHash 18 | txHash 19 | manager 20 | tokensReleased 21 | tokensWithdrawn 22 | tokensRevoked 23 | blockNumberCreated 24 | } 25 | } -------------------------------------------------------------------------------- /packages/token-distribution/ops/queries/network.graphql: -------------------------------------------------------------------------------- 1 | query GraphNetwork($blockNumber: Int) { 2 | graphNetwork(id: 1, block: { number: $blockNumber }) { 3 | id 4 | totalSupply 5 | } 6 | } -------------------------------------------------------------------------------- /packages/token-distribution/ops/queries/tokenLockWallets.graphql: -------------------------------------------------------------------------------- 1 | query TokenLockWallets($blockNumber: Int, $first: Int) { 2 | tokenLockWallets(block: { number: $blockNumber }, first: $first, orderBy: id) { 3 | id 4 | beneficiary 5 | managedAmount 6 | periods 7 | startTime 8 | endTime 9 | revocable 10 | releaseStartTime 11 | vestingCliffTime 12 | initHash 13 | txHash 14 | manager 15 | tokensReleased 16 | tokensWithdrawn 17 | tokensRevoked 18 | blockNumberCreated 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/token-distribution/ops/results.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphprotocol/contracts/cbda0fcc86239f8284cbdd18c8154c5a41b8aa52/packages/token-distribution/ops/results.csv -------------------------------------------------------------------------------- /packages/token-distribution/ops/tx-builder-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "chainId": "5", 4 | "createdAt": 1664999924896, 5 | "meta": { 6 | "name": "Vesting Contracts", 7 | "description": "", 8 | "txBuilderVersion": "1.11.1", 9 | "createdFromSafeAddress": "", 10 | "createdFromOwnerAddress": "", 11 | "checksum": "0xaa4f6084a39579ddecb1224904d703183c5086d1e3d7e63ba94a8b6819dd2122" 12 | }, 13 | "transactions": [ 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/token-distribution/ops/tx-builder.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | export interface BuilderTx { 5 | to: string 6 | data: string 7 | value: number | string 8 | contractMethod?: null 9 | contractInputsValues?: null 10 | } 11 | 12 | interface TxBuilderContents { 13 | createdAt: number 14 | chainId: string 15 | transactions: BuilderTx[] 16 | } 17 | 18 | export class TxBuilder { 19 | contents: TxBuilderContents 20 | outputFile: string 21 | 22 | constructor(chainId: string, _template?: string) { 23 | // Template file 24 | const template = _template ?? 'tx-builder-template.json' 25 | const templateFilename = path.join(__dirname, template) 26 | 27 | // Output file 28 | const dateTime = new Date().getTime() 29 | this.outputFile = path.join(__dirname, `tx-builder-${dateTime}.json`) 30 | 31 | // Load template 32 | this.contents = JSON.parse(fs.readFileSync(templateFilename, 'utf8')) 33 | this.contents.createdAt = dateTime 34 | this.contents.chainId = chainId 35 | } 36 | 37 | addTx(tx: BuilderTx) { 38 | this.contents.transactions.push({ ...tx, contractMethod: null, contractInputsValues: null }) 39 | } 40 | 41 | saveToFile() { 42 | fs.writeFileSync(this.outputFile, JSON.stringify(this.contents, null, 2)) 43 | return this.outputFile 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/token-distribution/prettier.config.cjs: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../prettier.config.cjs') 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | } 6 | -------------------------------------------------------------------------------- /packages/token-distribution/scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | yarn graphclient build 6 | yarn run compile -------------------------------------------------------------------------------- /packages/token-distribution/scripts/coverage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | yarn run compile 6 | COVERAGE=true npx hardhat coverage $@ 7 | -------------------------------------------------------------------------------- /packages/token-distribution/scripts/flatten: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUT_DIR="build/flatten" 4 | 5 | mkdir -p ${OUT_DIR} 6 | 7 | echo "Flattening contracts..." 8 | 9 | FILES=( 10 | "contracts/GraphTokenDistributor.sol" 11 | "contracts/GraphTokenLockSimple.sol" 12 | "contracts/GraphTokenLockWallet.sol" 13 | "contracts/GraphTokenLockManager.sol" 14 | ) 15 | 16 | for path in ${FILES[@]}; do 17 | IFS='/' 18 | parts=( $path ) 19 | name=${parts[${#parts[@]}-1]} 20 | echo "Flatten > ${name}" 21 | hardhat flatten "${path}" > "${OUT_DIR}/${name}" 22 | done 23 | 24 | echo "Done!" 25 | -------------------------------------------------------------------------------- /packages/token-distribution/scripts/prepublish: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TYPECHAIN_DIR=dist/types 4 | 5 | set -eo pipefail 6 | 7 | # Build contracts 8 | yarn run clean 9 | yarn run build 10 | 11 | # Refresh distribution folder 12 | rm -rf dist && mkdir -p dist 13 | mkdir -p ${TYPECHAIN_DIR}/_src 14 | cp -R build/abis/ dist/abis 15 | cp -R build/typechain/contracts/ ${TYPECHAIN_DIR}/_src 16 | cp -R deployments/ dist/deployments 17 | cp -R .openzeppelin/ dist/.openzeppelin 18 | 19 | ### Build Typechain bindings 20 | 21 | # Build and create TS declarations 22 | tsc -d ${TYPECHAIN_DIR}/_src/*.ts --outdir ${TYPECHAIN_DIR}/contracts --esModuleInterop 23 | # Copy back sources 24 | cp ${TYPECHAIN_DIR}/_src/*.ts ${TYPECHAIN_DIR}/contracts 25 | # Delete temporary src dir 26 | rm -rf ${TYPECHAIN_DIR}/_src 27 | -------------------------------------------------------------------------------- /packages/token-distribution/scripts/security: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Before running: 4 | # This tool requires to have solc installed. 5 | # Ensure that you have the binaries installed by pip3 in your path. 6 | # Install: https://github.com/crytic/slither#how-to-install 7 | # Usage: https://github.com/crytic/slither/wiki/Usage 8 | 9 | mkdir -p reports 10 | 11 | pip3 install --user slither-analyzer && \ 12 | yarn run build && \ 13 | 14 | echo "Analyzing contracts..." 15 | slither . &> reports/analyzer-report.log && \ 16 | 17 | echo "Done!" 18 | -------------------------------------------------------------------------------- /packages/token-distribution/scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect" 6 | TESTRPC_PORT=8545 7 | 8 | ### Functions 9 | 10 | evm_running() { 11 | nc -z localhost "$TESTRPC_PORT" 12 | } 13 | 14 | evm_start() { 15 | echo "Starting our own evm instance at port $TESTRPC_PORT" 16 | npx ganache-cli -m "$MNEMONIC" -i 1337 --gasLimit 8000000 --port "$TESTRPC_PORT" > /dev/null & 17 | evm_pid=$! 18 | } 19 | 20 | evm_kill() { 21 | if evm_running; then 22 | echo "Killing evm instance at port $TESTRPC_PORT" 23 | kill -9 $(lsof -i:$TESTRPC_PORT -t) 24 | fi 25 | } 26 | 27 | ### Setup evm 28 | 29 | # Gas reporter needs to run in its own evm instance 30 | if [ "$RUN_EVM" = true ]; then 31 | evm_kill 32 | evm_start 33 | sleep 5 34 | fi 35 | 36 | ### Main 37 | 38 | mkdir -p reports 39 | 40 | yarn run compile 41 | 42 | if [ "$RUN_EVM" = true ]; then 43 | # Run using the standalone evm instance 44 | npx hardhat test --network ganache 45 | result=$? 46 | else 47 | # Run using the default evm 48 | npx hardhat test "$@" 49 | result=$? 50 | fi 51 | 52 | ### Cleanup 53 | 54 | # Exit error mode so the evm instance always gets killed 55 | set +e 56 | result=0 57 | 58 | if [ "$RUN_EVM" = true ]; then 59 | evm_kill 60 | fi 61 | 62 | exit $result 63 | -------------------------------------------------------------------------------- /packages/token-distribution/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true, 10 | "incremental": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | useTabs: false, 4 | bracketSpacing: true, 5 | singleQuote: true, 6 | semi: false, 7 | plugins: ['prettier-plugin-solidity'], 8 | overrides: [ 9 | { 10 | files: '*.sol', 11 | options: { 12 | tabWidth: 4, 13 | singleQuote: false, 14 | }, 15 | }, 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /scripts/set-json-key-value: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set-json-key-value
-- [ ...] 3 | 4 | set -e 5 | 6 | if [ "$#" -lt 5 ]; then 7 | echo "Usage: $0
-- [ ...]" 8 | exit 1 9 | fi 10 | 11 | SECTION="$1" 12 | KEY="$2" 13 | VALUE="$3" 14 | 15 | # Find the position of '--' 16 | shift 3 17 | while [[ "$1" != "--" && "$#" -gt 0 ]]; do 18 | shift 19 | done 20 | 21 | if [ "$1" != "--" ]; then 22 | echo "Error: Missing '--' before file list" 23 | exit 1 24 | fi 25 | shift # Remove '--' 26 | 27 | for FILE in "$@"; do 28 | if [ ! -f "$FILE" ]; then 29 | echo "File not found: $FILE" 30 | continue 31 | fi 32 | 33 | jq --arg section "$SECTION" --arg key "$KEY" --arg value "$VALUE" \ 34 | '.[$section][$key] = $value' \ 35 | "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE" 36 | echo "Updated [$SECTION][$KEY] in $FILE" 37 | done 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "skipLibCheck": true, 10 | "resolveJsonModule": true, 11 | "outDir": "dist", 12 | "allowJs": true, 13 | "checkJs": false 14 | }, 15 | "include": ["**/*.ts", "**/*.js", "**/*.mjs", "**/*.cjs"], 16 | "exclude": ["node_modules", "dist", "build", "cache", "coverage"] 17 | } 18 | --------------------------------------------------------------------------------