|
| 1 | +# Graph Runtime Environment (GRE) |
| 2 | + |
| 3 | +GRE is a hardhat plugin that extends hardhat's runtime environment to inject additional functionality related to the usage of the Graph Protocol. |
| 4 | + |
| 5 | +### Features |
| 6 | + |
| 7 | +- Provides a simple interface to interact with protocol contracts |
| 8 | +- Exposes protocol configuration via graph config file and address book |
| 9 | +- Provides account management methods for convenience |
| 10 | +- Multichain! Supports both L1 and L2 layers of the protocol simultaneously |
| 11 | + |
| 12 | +### Usage |
| 13 | + |
| 14 | +#### Example |
| 15 | +Import GRE using `import './gre/gre'` on your hardhat config file and then: |
| 16 | + |
| 17 | +```js |
| 18 | +// Use L2 governor account to set the L1 token address on the L2 gateway |
| 19 | +const { l1, l2 } = hre.graph() |
| 20 | + |
| 21 | +const { GraphToken } = l1.contracts |
| 22 | + |
| 23 | +const { L2GraphTokenGateway } = l2.contracts |
| 24 | +const { governor } = await l2.getNamedAccounts() |
| 25 | + |
| 26 | +const tx = L2GraphTokenGateway.connect(governor).setL1TokenAddress(GraphToken.address) |
| 27 | +``` |
| 28 | + |
| 29 | +#### Network selection |
| 30 | + |
| 31 | +GRE supports both the L1 and L2 networks of the Graph Protocol by default. It will use hardhat's network defined via `--network` as the "main" network and then automatically detect which is the appropriate counterpart network in L1 or L2. |
| 32 | + |
| 33 | +Example: |
| 34 | + |
| 35 | +```bash |
| 36 | +# L1: goerli and L2: arbitrum-goerli |
| 37 | +hh console --network goerli |
| 38 | + |
| 39 | +# L1: mainnet and L2: arbitrum-one |
| 40 | +hh console --network arbitrum-one |
| 41 | + |
| 42 | +# L1: mainnet and L2: arbitrum-one > same as previous |
| 43 | +hh console --network mainnet |
| 44 | +``` |
| 45 | + |
| 46 | +#### Configuration |
| 47 | + |
| 48 | +To use GRE you'll need to configure the target networks. That is done via either hardhat's config file using the `networks` [config field](https://hardhat.org/hardhat-runner/docs/config#json-rpc-based-networks) or by passing the appropriate arguments to `hre.graph()` initializer. |
| 49 | + |
| 50 | +__Note__: The "main" network, defined by hardhat's `--network` flag _MUST_ be properly configured for GRE to initialize successfully. It's not necessary to configure the counterpart network if you don't plan on using it. |
| 51 | + |
| 52 | +**Hardhat: Network config** |
| 53 | +```js |
| 54 | +networks: { |
| 55 | + goerli: { |
| 56 | + chainId: 5, |
| 57 | + url: `https://goerli.infura.io/v3/123456` |
| 58 | + accounts: { |
| 59 | + mnemonic: 'test test test test test test test test test test test test', |
| 60 | + }, |
| 61 | + graphConfig: 'config/graph.goerli.yml' |
| 62 | + }, |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +Fields: |
| 67 | +- **(_REQUIRED_) chainId**: the chainId of the network. This field is not required by hardhat but it's used by GRE to simplify the API. |
| 68 | +- **(_REQUIRED_) url**: the RPC endpoint of the network. |
| 69 | +- **(_OPTIONAL_) accounts**: the accounts to use on the network. These will be used by the account management functions on GRE. |
| 70 | +- **(_OPTIONAL_) graphConfig**: the path to the graph config file for the network. |
| 71 | + |
| 72 | +**Hardhat: Graph config** |
| 73 | + |
| 74 | +Additionally, the plugin adds a new config field to hardhat's config file: `graphConfig`. This can be used used to define defaults for the graph config file. |
| 75 | + |
| 76 | + |
| 77 | +```js |
| 78 | +... |
| 79 | +networks: { |
| 80 | +... |
| 81 | +}, |
| 82 | +graph: { |
| 83 | + addressBook: 'addresses.json' |
| 84 | + l1GraphConfig: 'config/graph.mainnet.yml' |
| 85 | + l2GraphConfig: 'config/graph.arbitrum-one.yml' |
| 86 | +} |
| 87 | +... |
| 88 | +``` |
| 89 | + |
| 90 | +Fields: |
| 91 | +- **(_OPTIONAL_) addressBook**: the path to the address book. |
| 92 | +- **(_REQUIRED_) l1GraphConfig**: default path to the graph config file for L1 networks. This will be used if the `graphConfig` field is not defined on the network config. |
| 93 | +- **(_REQUIRED_) l2GraphConfig**: default path to the graph config file for L2 networks. This will be used if the `graphConfig` field is not defined on the network config. |
| 94 | + |
| 95 | +**Options: Graph initializer** |
| 96 | + |
| 97 | +The GRE initializer also allows you to set the address book and the graph config files like so: |
| 98 | +```js |
| 99 | +const graph = hre.graph({ |
| 100 | + addressBook: 'addresses.json', |
| 101 | + l1GraphConfig: 'config/graph.mainnet.yml' |
| 102 | + l2GraphConfig: 'config/graph.arbitrum-one.yml' |
| 103 | +}) |
| 104 | + |
| 105 | +// Here graphConfig will apply only to the "main" network given by --network |
| 106 | +const graph = hre.graph({ |
| 107 | + addressBook: 'addresses.json', |
| 108 | + graphConfig: 'config/graph.mainnet.yml' |
| 109 | +}) |
| 110 | +``` |
| 111 | + |
| 112 | +**Config priority** |
| 113 | + |
| 114 | +The path to the graph config and the address book can be set in multiple ways. The plugin will use the following order to determine the path to the graph config file: |
| 115 | + |
| 116 | +1) `hre.graph({ ... })` init parameters `l1GraphConfigPath` and `l2GraphConfigPath` |
| 117 | +2) `hre.graph({ ...})` init parameter graphConfigPath (but only for the "main" network) |
| 118 | +3) `networks.<NETWORK_NAME>.graphConfig` network config parameter `graphConfig` in hardhat config file |
| 119 | +4) `graph.l<X>GraphConfig` graph config parameters `l1GraphConfig` and `l2GraphConfig` in hardhat config file |
| 120 | + |
| 121 | +The priority for the address book is: |
| 122 | +1) `hre.graph({ ... })` init parameter `addressBook` |
| 123 | +2) `graph.addressBook` graph config parameter `addressBook` in hardhat config file |
| 124 | + |
| 125 | +### API |
| 126 | + |
| 127 | +GRE exposes functionality via a simple API: |
| 128 | + |
| 129 | +```js |
| 130 | +const graph = hre.graph() |
| 131 | + |
| 132 | +// To access the L1 object |
| 133 | +graph.l1 |
| 134 | + |
| 135 | +// To access the L2 object |
| 136 | +graph.l2 |
| 137 | +``` |
| 138 | + |
| 139 | +The interface for both `l1` and `l2` objects looks like this: |
| 140 | + |
| 141 | +```ts |
| 142 | +export interface GraphNetworkEnvironment { |
| 143 | + chainId: number |
| 144 | + contracts: NetworkContracts |
| 145 | + graphConfig: any |
| 146 | + addressBook: AddressBook |
| 147 | + getNamedAccounts: () => Promise<NamedAccounts> |
| 148 | + getTestAccounts: () => Promise<SignerWithAddress[]> |
| 149 | + getDeployer: () => Promise<SignerWithAddress> |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +**ChainId** |
| 154 | + |
| 155 | +The chainId of the network. |
| 156 | + |
| 157 | +**Contracts** |
| 158 | + |
| 159 | +Returns an object with all the contracts available in the network. Connects using a provider created with the URL specified in hardhat's network configuration (it doesn't use the usual hardhat `hre.ethers.provider`). |
| 160 | + |
| 161 | +```js |
| 162 | +> const graph = hre.graph() |
| 163 | + |
| 164 | +// Print curation default reserve ratio on L1 |
| 165 | +> await g.l1.contracts.Curation.defaultReserveRatio() |
| 166 | +500000 |
| 167 | +``` |
| 168 | + |
| 169 | +**Graph Config** |
| 170 | + |
| 171 | +Returns an object that grants raw access to the graph config file for the protocol. The graph config file is a YAML file that contains all the parameters with which the protocol was deployed. |
| 172 | + |
| 173 | +> TODO: add better APIs to interact with the graph config file. |
| 174 | +
|
| 175 | +**Address Book** |
| 176 | + |
| 177 | +Returns an object that allows interacting with the address book. |
| 178 | + |
| 179 | +```js |
| 180 | +> const graph = hre.graph() |
| 181 | +> graph.l1.addressBook.getEntry('Curation') |
| 182 | +{ |
| 183 | + address: '0xE59B4820dDE28D2c235Bd9A73aA4e8716Cb93E9B', |
| 184 | + initArgs: [ |
| 185 | + '0x48eD7AfbaB432d1Fc6Ea84EEC70E745d9DAcaF3B', |
| 186 | + '0x2DFDC3e11E035dD96A4aB30Ef67fab4Fb6EC01f2', |
| 187 | + '0x8bEd0a89F18a801Da9dEA994D475DEa74f75A059', |
| 188 | + '500000', |
| 189 | + '10000', |
| 190 | + '1000000000000000000' |
| 191 | + ], |
| 192 | + creationCodeHash: '0x25a7b6cafcebb062169bc25fca9bcce8f23bd7411235859229ae3cc99b9a7d58', |
| 193 | + runtimeCodeHash: '0xaf2d63813a0e5059f63ec46e1b280eb9d129d5ad548f0cdd1649d9798fde10b6', |
| 194 | + txHash: '0xf1b1f0f28b80068bcc9fd6ef475be6324a8b23cbdb792f7344f05ce00aa997d7', |
| 195 | + proxy: true, |
| 196 | + implementation: { |
| 197 | + address: '0xAeaA2B058539750b740E858f97159E6856948670', |
| 198 | + creationCodeHash: '0x022576ab4b739ee17dab126ea7e5a6814bda724aa0e4c6735a051b38a76bd597', |
| 199 | + runtimeCodeHash: '0xc7b1f9bef01ef92779aab0ae9be86376c47584118c508f5b4e612a694a4aab93', |
| 200 | + txHash: '0x400bfb7b6c384363b859a66930590507ddca08ebedf64b20c4b5f6bc8e76e125' |
| 201 | + } |
| 202 | +} |
| 203 | +``` |
| 204 | + |
| 205 | +**Account management: getNamedAccounts** |
| 206 | +Returns an object with all the named accounts available in the network. Named accounts are accounts that have special roles in the protocol, they are defined in the graph config file. |
| 207 | + |
| 208 | +```js |
| 209 | +> const graph = hre.graph() |
| 210 | +> const namedAccounts = await g.l1.getNamedAccounts() |
| 211 | +> namedAccounts.governor.address |
| 212 | +'0xf1135bFF22512FF2A585b8d4489426CE660f204c' |
| 213 | +``` |
| 214 | + |
| 215 | +The accounts are initialized from the graph config file but if the correct mnemonic or private key is provided via hardhat network configuration then they will be fully capable of signing transactions. |
| 216 | + |
| 217 | +**Account management: getTestAccounts** |
| 218 | +Returns an object with accounts which can be used for testing/interacting with the protocol. These are obtained from hardhat's network configuration using the provided mnemonic or private key. |
| 219 | + |
| 220 | +**Account management: getDeployer** |
| 221 | +Returns an object with the would-be deployer account. The deployer is by convention the first (index 0) account derived from the mnemonic or private key provided via hardhat network configuration. |
| 222 | + |
| 223 | +It's important to note that the deployer is not a named account as it's derived from the provided mnemonic so it won't necessarily match the actual deployer for a given deployment. It's the account that would be used to deploy the protocol with the current configuration. It's not possible at the moment to recover the actual deployer account from a deployed protocol. |
0 commit comments