From 9e3fc5d9ae0095969fee13958a58e5c923e75844 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Fri, 9 Sep 2022 15:40:08 +0100 Subject: [PATCH 01/27] Add minimal ts project --- ethersjs-api-check/.gitignore | 4 ++++ ethersjs-api-check/package.json | 15 +++++++++++++++ ethersjs-api-check/src/index.ts | 1 + ethersjs-api-check/tsconfig.json | 10 ++++++++++ 4 files changed, 30 insertions(+) create mode 100644 ethersjs-api-check/.gitignore create mode 100644 ethersjs-api-check/package.json create mode 100644 ethersjs-api-check/src/index.ts create mode 100644 ethersjs-api-check/tsconfig.json diff --git a/ethersjs-api-check/.gitignore b/ethersjs-api-check/.gitignore new file mode 100644 index 0000000000..1fd48a7d52 --- /dev/null +++ b/ethersjs-api-check/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +node_modules +dist + diff --git a/ethersjs-api-check/package.json b/ethersjs-api-check/package.json new file mode 100644 index 0000000000..4368286cfb --- /dev/null +++ b/ethersjs-api-check/package.json @@ -0,0 +1,15 @@ +{ + "name": "ethersjs-api-check", + "version": "1.0.0", + "description": "runs ethers.js against an api to check compatibility", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc --build" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "typescript": "^4.8.3" + } +} diff --git a/ethersjs-api-check/src/index.ts b/ethersjs-api-check/src/index.ts new file mode 100644 index 0000000000..940a3ff0ec --- /dev/null +++ b/ethersjs-api-check/src/index.ts @@ -0,0 +1 @@ +console.log("Hello world!"); diff --git a/ethersjs-api-check/tsconfig.json b/ethersjs-api-check/tsconfig.json new file mode 100644 index 0000000000..64ef675352 --- /dev/null +++ b/ethersjs-api-check/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES2016", + "module": "ES6", + "esModuleInterop": true, + "strict": true, + "rootDir": "src", + "outDir": "dist" + } +} From 9ebdd192896c4c12a26ce62788af584ae6d733ae Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Fri, 9 Sep 2022 15:41:34 +0100 Subject: [PATCH 02/27] Add ethers.js dependency --- ethersjs-api-check/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethersjs-api-check/package.json b/ethersjs-api-check/package.json index 4368286cfb..78eb781384 100644 --- a/ethersjs-api-check/package.json +++ b/ethersjs-api-check/package.json @@ -5,11 +5,14 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc --build" + "build": "tsc --build" }, "author": "", "license": "ISC", "devDependencies": { "typescript": "^4.8.3" + }, + "dependencies": { + "ethers": "^5.7.0" } } From 11fa86e2d5cb531862d55d262b7d246643eb3469 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Fri, 9 Sep 2022 17:57:52 +0100 Subject: [PATCH 03/27] Add etherejs api test (currently failing) Test tries to get the block --- e2e_test/e2e_test.go | 19 +++++++++++++++++++ ethersjs-api-check/package.json | 4 +++- ethersjs-api-check/src/index.ts | 13 ++++++++++++- ethersjs-api-check/tsconfig.json | 3 ++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index aae8ef4407..d79ad56af7 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "os/exec" "sync" "testing" "time" @@ -451,3 +452,21 @@ func pruneStateOfBlock(ctx context.Context, node *test.Node, blockHash common.Ha return nil } + +func TestEthersJSCompatibility(t *testing.T) { + ac := test.AccountConfig(1, 1) + gc, ec, err := test.BuildConfig(ac) + require.NoError(t, err) + network, shutdown, err := test.NewNetwork(ac, gc, ec) + require.NoError(t, err) + defer shutdown() + // Note the "--unhandled-rejections=strict" flag causes node to raise + // unhandled promise rejections as exceptions, and if the execption is not + // handled that will result in a non 0 exit code for the program. + cmd := exec.Command("node", "--unhandled-rejections=strict", "../ethersjs-api-check/dist/index.js", network[0].Node.HTTPEndpoint()) + output, err := cmd.CombinedOutput() + if err != nil { + println(string(output)) + } + require.NoError(t, err) +} diff --git a/ethersjs-api-check/package.json b/ethersjs-api-check/package.json index 78eb781384..f5750356cb 100644 --- a/ethersjs-api-check/package.json +++ b/ethersjs-api-check/package.json @@ -10,9 +10,11 @@ "author": "", "license": "ISC", "devDependencies": { + "@types/node": "^18.7.16", "typescript": "^4.8.3" }, "dependencies": { "ethers": "^5.7.0" - } + }, + "type": "module" } diff --git a/ethersjs-api-check/src/index.ts b/ethersjs-api-check/src/index.ts index 940a3ff0ec..456372ba88 100644 --- a/ethersjs-api-check/src/index.ts +++ b/ethersjs-api-check/src/index.ts @@ -1 +1,12 @@ -console.log("Hello world!"); +import {ethers} from "ethers"; + +// argv has the arguments index zero is node index 1 is this file and index2 is the network address +const provider = new ethers.providers.JsonRpcProvider(process.argv[2]); + + +async function gb() { + let b = await provider.getBlock("latest") + console.log(b) +} + +gb(); diff --git a/ethersjs-api-check/tsconfig.json b/ethersjs-api-check/tsconfig.json index 64ef675352..7b6d06e2c4 100644 --- a/ethersjs-api-check/tsconfig.json +++ b/ethersjs-api-check/tsconfig.json @@ -5,6 +5,7 @@ "esModuleInterop": true, "strict": true, "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "moduleResolution": "node" } } From 70232a067d1507941f538315ba4eaf55205c51be Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Fri, 9 Sep 2022 18:06:21 +0100 Subject: [PATCH 04/27] Add dummy data for gas limit field --- internal/ethapi/api.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 441fc3f6b5..6bf21b90f3 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -708,10 +708,14 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) - if err == nil && number == rpc.PendingBlockNumber { - // Pending blocks need to nil out a few fields - for _, field := range []string{"hash", "nonce", "miner"} { - response[field] = nil + + if err == nil { + addDummyFields(response) + if number == rpc.PendingBlockNumber { + // Pending blocks need to nil out a few fields + for _, field := range []string{"hash", "nonce", "miner"} { + response[field] = nil + } } } return response, err @@ -724,11 +728,20 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByHash(ctx, hash) if block != nil { - return s.rpcMarshalBlock(ctx, block, true, fullTx) + result, err := s.rpcMarshalBlock(ctx, block, true, fullTx) + if err != nil { + return nil, err + } + addDummyFields(result) + return result, nil } return nil, err } +func addDummyFields(block map[string]interface{}) { + block["gasLimit"] = 0 +} + // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true // all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { From 33de2a5e678217b1a9789cfd29b0e4740a7b9b2e Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Fri, 9 Sep 2022 18:42:17 +0100 Subject: [PATCH 05/27] Build ethersjs project before executing test --- e2e_test/e2e_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index d79ad56af7..9616f6f140 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -460,6 +460,15 @@ func TestEthersJSCompatibility(t *testing.T) { network, shutdown, err := test.NewNetwork(ac, gc, ec) require.NoError(t, err) defer shutdown() + + buildCmd := exec.Command("npm", "run", "build") + buildCmd.Dir = "../ethersjs-api-check" + buildOutput, err := buildCmd.CombinedOutput() + if err != nil { + println(string(buildOutput)) + } + require.NoError(t, err) + // Note the "--unhandled-rejections=strict" flag causes node to raise // unhandled promise rejections as exceptions, and if the execption is not // handled that will result in a non 0 exit code for the program. From 8e2c1c9aad3fb3077b8c8c23a151ec1654a90520 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Mon, 12 Sep 2022 11:31:41 +0100 Subject: [PATCH 06/27] Return real gas limit in place of dummy data --- internal/ethapi/api.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 6bf21b90f3..e779587689 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -710,7 +710,10 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil { - addDummyFields(response) + numhash := rpc.BlockNumberOrHash{ + BlockNumber: &number, + } + addEthCompatibilityFields(ctx, response, s.b, numhash) if number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -732,14 +735,22 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha if err != nil { return nil, err } - addDummyFields(result) + numhash := rpc.BlockNumberOrHash{ + BlockHash: &hash, + } + addEthCompatibilityFields(ctx, result, s.b, numhash) return result, nil } return nil, err } -func addDummyFields(block map[string]interface{}) { - block["gasLimit"] = 0 +// addEthCompatibilityFields seeks to work around the incompatibility of celo +// and ethers.js (and potentially other web3 clients) by adding fields to our +// rpc response that ethers.js depends upon. +// See https://github.com/celo-org/celo-blockchain/issues/1945 +func addEthCompatibilityFields(ctx context.Context, block map[string]interface{}, b Backend, numhash rpc.BlockNumberOrHash) { + gasLimit := b.GetBlockGasLimit(ctx, numhash) + block["gasLimit"] = hexutil.Uint64(gasLimit) } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true From aec0159e57969e66e772e679b253d5352db3e9ff Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Mon, 12 Sep 2022 12:39:26 +0100 Subject: [PATCH 07/27] Return baseFee if it is acessible --- internal/ethapi/api.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e779587689..b650766338 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -710,10 +710,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil { - numhash := rpc.BlockNumberOrHash{ - BlockNumber: &number, - } - addEthCompatibilityFields(ctx, response, s.b, numhash) + addEthCompatibilityFields(ctx, response, s.b, block.Header()) if number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -735,10 +732,7 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha if err != nil { return nil, err } - numhash := rpc.BlockNumberOrHash{ - BlockHash: &hash, - } - addEthCompatibilityFields(ctx, result, s.b, numhash) + addEthCompatibilityFields(ctx, result, s.b, block.Header()) return result, nil } return nil, err @@ -748,9 +742,26 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha // and ethers.js (and potentially other web3 clients) by adding fields to our // rpc response that ethers.js depends upon. // See https://github.com/celo-org/celo-blockchain/issues/1945 -func addEthCompatibilityFields(ctx context.Context, block map[string]interface{}, b Backend, numhash rpc.BlockNumberOrHash) { +func addEthCompatibilityFields(ctx context.Context, block map[string]interface{}, b Backend, header *types.Header) { + hash := header.Hash() + numhash := rpc.BlockNumberOrHash{ + BlockHash: &hash, + } gasLimit := b.GetBlockGasLimit(ctx, numhash) block["gasLimit"] = hexutil.Uint64(gasLimit) + + // Providing nil as the currency address gets the gas price minimum for the native celo asset. + baseFee, err := b.GasPriceMinimumForHeader(ctx, nil, header) + + // GasPriceMinimumForHeader can return an error + non nil baseFee, an error + // and nil base fee or a base fee and a nil error. In all cases where a + // base fee is returned we want to add it as a field and if there was an + // error and nil base fee we log the failure. + if err != nil && baseFee == nil { + log.Debug("Not adding gasPriceMinimum to RPC response, failed to retrieve gas price minimum", "block", header.Number.Uint64(), "err", err) + return + } + block["baseFeePerGas"] = (*hexutil.Big)(baseFee) } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true From 84bd94c7c1ca5783ddf765ab4367368494326834 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 13 Sep 2022 16:37:26 +0100 Subject: [PATCH 08/27] Use framework for ethers.js compatibility tests Instead of running a script we now use the mocha testing framework which provides much better output and makes it much easier to add testcases. --- e2e_test/e2e_test.go | 42 ++++++++++++++++++++---------- ethersjs-api-check/package.json | 13 ++++++---- ethersjs-api-check/src/index.ts | 12 --------- ethersjs-api-check/test/test.ts | 44 ++++++++++++++++++++++++++++++++ ethersjs-api-check/tsconfig.json | 2 +- 5 files changed, 82 insertions(+), 31 deletions(-) delete mode 100644 ethersjs-api-check/src/index.ts create mode 100644 ethersjs-api-check/test/test.ts diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 9616f6f140..6fcbdb3ad8 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -461,21 +461,37 @@ func TestEthersJSCompatibility(t *testing.T) { require.NoError(t, err) defer shutdown() - buildCmd := exec.Command("npm", "run", "build") - buildCmd.Dir = "../ethersjs-api-check" - buildOutput, err := buildCmd.CombinedOutput() - if err != nil { - println(string(buildOutput)) - } + ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) + defer cancel() + + num, err := network[0].WsClient.BlockNumber(ctx) require.NoError(t, err) - // Note the "--unhandled-rejections=strict" flag causes node to raise - // unhandled promise rejections as exceptions, and if the execption is not - // handled that will result in a non 0 exit code for the program. - cmd := exec.Command("node", "--unhandled-rejections=strict", "../ethersjs-api-check/dist/index.js", network[0].Node.HTTPEndpoint()) + // Execute typescript tests to check ethers.js compatibility. + // + // The '--networkaddr' and '--blocknum' flags are npm config variables, the + // values become available under 'process.env.npm_config_networkaddr' and + // 'process.env.npm_config_blocknum' in typescript test. Everything after + // '--' are flags that are passed to mocha and these flags are controlling + // which tests to run. + cmd := exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") + cmd.Dir = "../ethersjs-api-check/" output, err := cmd.CombinedOutput() - if err != nil { - println(string(output)) - } + println(string(output)) + require.NoError(t, err) + + err = network[0].Tracker.AwaitBlock(ctx, num+1) + require.NoError(t, err) + block := network[0].Tracker.GetProcessedBlock(num) + + // Prune state + err = pruneStateOfBlock(ctx, network[0], block.Hash()) + require.NoError(t, err) + + // Execute typescript tests to check what happens with a pruned block. + cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "block with pruned") + cmd.Dir = "../ethersjs-api-check/" + output, err = cmd.CombinedOutput() + println(string(output)) require.NoError(t, err) } diff --git a/ethersjs-api-check/package.json b/ethersjs-api-check/package.json index f5750356cb..6af7981b7b 100644 --- a/ethersjs-api-check/package.json +++ b/ethersjs-api-check/package.json @@ -4,17 +4,20 @@ "description": "runs ethers.js against an api to check compatibility", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc --build" + "test": "mocha -r ts-node/register test/*.ts" }, "author": "", "license": "ISC", "devDependencies": { + "@types/chai": "^4.3.3", + "@types/mocha": "^9.1.1", "@types/node": "^18.7.16", + "chai": "^4.3.6", + "mocha": "^10.0.0", "typescript": "^4.8.3" }, "dependencies": { - "ethers": "^5.7.0" - }, - "type": "module" + "ethers": "^5.7.0", + "ts-node": "^10.9.1" + } } diff --git a/ethersjs-api-check/src/index.ts b/ethersjs-api-check/src/index.ts deleted file mode 100644 index 456372ba88..0000000000 --- a/ethersjs-api-check/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {ethers} from "ethers"; - -// argv has the arguments index zero is node index 1 is this file and index2 is the network address -const provider = new ethers.providers.JsonRpcProvider(process.argv[2]); - - -async function gb() { - let b = await provider.getBlock("latest") - console.log(b) -} - -gb(); diff --git a/ethersjs-api-check/test/test.ts b/ethersjs-api-check/test/test.ts new file mode 100644 index 0000000000..3b578ec342 --- /dev/null +++ b/ethersjs-api-check/test/test.ts @@ -0,0 +1,44 @@ +import {ethers} from "ethers"; +import {assert} from 'chai'; +import 'mocha'; + +describe('ethers.js compatibility', () => { + + it('block retrieved with gasLimit', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + let block = await provider.getBlock(process.env.npm_config_blocknum as string); + + // These assertions trigger on undefined or null + assert.notEqual(block, null); + assert.notEqual(block.gasLimit, null); + }); + + it('EIP-1559 transactions supported', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + + // The fee data is the construct used to determine if EIP-1559 transactions are supported, if it contains max + let feeData = await provider.getFeeData(); + + // These assertions trigger on undefined or null + assert.notEqual(feeData, null); + // If the following 2 fields are set then the network is assumed to support EIP-1559 transactions. + assert.notEqual(feeData.maxFeePerGas, null); + assert.notEqual(feeData.maxPriorityFeePerGas, null); + // We check the other 2 fields for completeness, they should also be set. + assert.notEqual(feeData.gasPrice, null); + assert.notEqual(feeData.lastBaseFeePerGas, null); + }); + + // Our blockchain client implementation returns a default gas limit when the + // actual gas limit cannot be retrieved. We cannot check fee data against a + // pruned block because getFeeData always requests the latest block. + it('block with pruned state still reports gas limit', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + let block = await provider.getBlock(process.env.npm_config_blocknum as string); + + // These assertions trigger on undefined or null + assert.notEqual(block, null); + assert.notEqual(block.gasLimit, null); + }); + +}); diff --git a/ethersjs-api-check/tsconfig.json b/ethersjs-api-check/tsconfig.json index 7b6d06e2c4..9b2743b765 100644 --- a/ethersjs-api-check/tsconfig.json +++ b/ethersjs-api-check/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "ES2016", - "module": "ES6", + "module": "commonjs", "esModuleInterop": true, "strict": true, "rootDir": "src", From c624df43407d6bc537b1872018308256753a974d Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 09:27:28 +0100 Subject: [PATCH 09/27] Store package lock --- ethersjs-api-check/.gitignore | 1 - ethersjs-api-check/package-lock.json | 1344 ++++++++++++++++++++++++++ 2 files changed, 1344 insertions(+), 1 deletion(-) create mode 100644 ethersjs-api-check/package-lock.json diff --git a/ethersjs-api-check/.gitignore b/ethersjs-api-check/.gitignore index 1fd48a7d52..4175924eca 100644 --- a/ethersjs-api-check/.gitignore +++ b/ethersjs-api-check/.gitignore @@ -1,4 +1,3 @@ -package-lock.json node_modules dist diff --git a/ethersjs-api-check/package-lock.json b/ethersjs-api-check/package-lock.json new file mode 100644 index 0000000000..e511c2e623 --- /dev/null +++ b/ethersjs-api-check/package-lock.json @@ -0,0 +1,1344 @@ +{ + "name": "ethersjs-api-check", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" + }, + "@ethersproject/networks": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.0.tgz", + "integrity": "sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA==", + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.0.tgz", + "integrity": "sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA==", + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.0.tgz", + "integrity": "sha512-ApHcbbj+muRASVDSCl/tgxaH2LBkRMEYfLOLVa0COipx0+nlu0QKet7U2lEg0vdkh8XRSLf2nd1f1Uk9SrVSGA==", + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "@types/chai": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", + "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "dev": true + }, + "@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "@types/node": { + "version": "18.7.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz", + "integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==", + "dev": true + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "ethers": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.0.tgz", + "integrity": "sha512-5Xhzp2ZQRi0Em+0OkOcRHxPzCfoBfgtOQA+RUylSkuHbhTEaQklnYi2hsWbRgs3ztJsXVXd9VKBcO1ScWL8YfA==", + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.0", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.0", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.0", + "@ethersproject/wordlists": "5.7.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + } + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} From 9d175c12f6aaada484a958e057de309e62e32667 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 09:54:12 +0100 Subject: [PATCH 10/27] Add make rule to install ethersjs project deps --- Makefile | 9 ++++++++- README.md | 11 ++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 90f5f0f212..ac34747c64 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ .PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 .PHONY: geth-darwin geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 -.PHONY: prepare-system-contracts +.PHONY: prepare prepare-system-contracts prepare-ethersjs-project GOBIN = ./build/bin GO ?= latest @@ -45,6 +45,13 @@ geth: @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." +prepare: prepare-system-contracts prepare-ethersjs-project + +prepare-ethersjs-project: ./ethersjs-api-check/node_modules + +./ethersjs-api-check/node_modules: ./ethersjs-api-check/package.json ./ethersjs-api-check/package-lock.json + @cd ./ethersjs-api-check && npm ci + # This rule checks out celo-monorepo under MONOREPO_PATH at the commit contained in # monorepo_commit and compiles the system solidity contracts. It then copies the # compiled contracts from the monorepo to the compiled-system-contracts, so diff --git a/README.md b/README.md index fc73e4f3ef..489563b77f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,12 @@ The Celo blockchain client comes with several wrappers/executables found in the ## Running tests -Prior to running tests you will need to run `make prepare-system-contracts`. +Prior to running tests you will need to run `make prepare`, this will run two sub rules. + +Without first running this `make prepare`, certain tests will fail. + +### prepare-system-contracts + This will shallow checkout the [celo-monorepo](https://github.com/celo-org/celo-monorepo) under `../.celo-blockchain-monorepo-checkout` relative to this project's root at the @@ -86,8 +91,8 @@ those checked out by the `prepare-system-contracts` rule, and the checkouts created by the `prepare-system-contracts` rule should not be manually modifed, aside from changing the contract source. - -Without first running this make rule, certain tests will fail. +### prepare-ethersjs-project +This will install dependencies for the `ethersjs-api-check` typescript project. ## Running Celo From cb1479c67089f9c4987439df57dcb7d98f42346d Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 10:08:32 +0100 Subject: [PATCH 11/27] Update ci to prepare ehtersjs project --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index e85ea1264d..dcbe709472 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -309,6 +309,7 @@ jobs: - attach_workspace: at: ~/repos - *restore-go-mod-cache + - run: make prepare-ethersjs-project - run: go get github.com/jstemmer/go-junit-report - run: name: Run tests @@ -330,6 +331,7 @@ jobs: - attach_workspace: at: ~/repos - *restore-go-mod-cache + - run: make prepare-ethersjs-project - run: go get github.com/jstemmer/go-junit-report - run: name: Run tests @@ -351,6 +353,7 @@ jobs: - attach_workspace: at: ~/repos - *restore-go-mod-cache + - run: make prepare-ethersjs-project # Run the tests with coverage parse the coverage and output the summary - run: name: Run tests and print coverage summary From bd71fd1f4ca0e5bb85e8c3af82ac574e7c865c62 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 11:34:03 +0100 Subject: [PATCH 12/27] Add dockerfile for a node/golang CI executor Update CI to use new docker image, since we now need to run node and npm as part of our tests. --- .circleci/config.yml | 2 +- .circleci/node-golang-dockerfile/Dockerfile | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .circleci/node-golang-dockerfile/Dockerfile diff --git a/.circleci/config.yml b/.circleci/config.yml index dcbe709472..cebd507571 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -114,7 +114,7 @@ parameters: executors: golang: docker: - - image: circleci/golang:1.16 + - image: "us.gcr.io/celo-testnet/circleci-node12-golang1.17.5" working_directory: ~/repos/geth environment: # Change the go modules to be cached under ~/repos so that we can add diff --git a/.circleci/node-golang-dockerfile/Dockerfile b/.circleci/node-golang-dockerfile/Dockerfile new file mode 100644 index 0000000000..3039e7bae1 --- /dev/null +++ b/.circleci/node-golang-dockerfile/Dockerfile @@ -0,0 +1,6 @@ +# This has been pushed to us.gcr.io/celo-testnet/circleci-node12-golang1.17.5 +FROM circleci/node:12 + +COPY --from=circleci/golang:1.17.5 /usr/local/go/ /usr/local/go/ + +ENV PATH="/usr/local/go/bin:${PATH}" From 9895733f4c7df867e96028bc3ea179776c2f7a61 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 14:35:53 +0100 Subject: [PATCH 13/27] Run e2e coverage CI tests verbosely --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cebd507571..910bf5b45e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -358,7 +358,7 @@ jobs: - run: name: Run tests and print coverage summary command: | - go test -coverprofile cov.out -coverpkg ./consensus/istanbul/... ./e2e_test + go test -v -coverprofile cov.out -coverpkg ./consensus/istanbul/... ./e2e_test go run tools/parsecov/main.go -packagePrefix github.com/celo-org/celo-blockchain/ cov.out > summary cat summary From 45e386b3deac4a7313ca29a009a11a2095427ed0 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 14:39:14 +0100 Subject: [PATCH 14/27] Add debug --- e2e_test/e2e_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 6fcbdb3ad8..95f7fa1aef 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "os" "os/exec" "sync" "testing" @@ -474,9 +475,18 @@ func TestEthersJSCompatibility(t *testing.T) { // 'process.env.npm_config_blocknum' in typescript test. Everything after // '--' are flags that are passed to mocha and these flags are controlling // which tests to run. - cmd := exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") + wd, err := os.Getwd() + require.NoError(t, err) + println("current dir", wd) + cmd := exec.Command("ls") cmd.Dir = "../ethersjs-api-check/" output, err := cmd.CombinedOutput() + println("ls output", string(output)) + require.NoError(t, err) + + cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") + cmd.Dir = "../ethersjs-api-check/" + output, err = cmd.CombinedOutput() println(string(output)) require.NoError(t, err) From dd1761990f150b082d7e6f03088ff6cbd83e3418 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 14 Sep 2022 15:24:08 +0100 Subject: [PATCH 15/27] Add more debug --- e2e_test/e2e_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 95f7fa1aef..9768531d22 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -486,6 +486,7 @@ func TestEthersJSCompatibility(t *testing.T) { cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") cmd.Dir = "../ethersjs-api-check/" + println("executing mocha test with", cmd.String()) output, err = cmd.CombinedOutput() println(string(output)) require.NoError(t, err) @@ -501,6 +502,7 @@ func TestEthersJSCompatibility(t *testing.T) { // Execute typescript tests to check what happens with a pruned block. cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "block with pruned") cmd.Dir = "../ethersjs-api-check/" + println("executing mocha test with", cmd.String()) output, err = cmd.CombinedOutput() println(string(output)) require.NoError(t, err) From a0174f4e2ae1069c5d4a121829e9311cc0fe9c0c Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Thu, 15 Sep 2022 13:45:32 +0100 Subject: [PATCH 16/27] Change address format The IPV6 addresses returned from the geth node were not working on CI so we convert them to IPV4 addresses. --- e2e_test/e2e_test.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 9768531d22..209f1ade2a 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" "math/big" - "os" "os/exec" + "strings" "sync" "testing" "time" @@ -475,19 +475,14 @@ func TestEthersJSCompatibility(t *testing.T) { // 'process.env.npm_config_blocknum' in typescript test. Everything after // '--' are flags that are passed to mocha and these flags are controlling // which tests to run. - wd, err := os.Getwd() - require.NoError(t, err) - println("current dir", wd) - cmd := exec.Command("ls") - cmd.Dir = "../ethersjs-api-check/" - output, err := cmd.CombinedOutput() - println("ls output", string(output)) - require.NoError(t, err) - cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") + // The tests don't seem to work on CI with IPV6 addresses so we convert to IPV4 here + addr := strings.Replace(network[0].Node.HTTPEndpoint(), "[::]", "127.0.0.1", 1) + + cmd := exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") cmd.Dir = "../ethersjs-api-check/" println("executing mocha test with", cmd.String()) - output, err = cmd.CombinedOutput() + output, err := cmd.CombinedOutput() println(string(output)) require.NoError(t, err) @@ -500,7 +495,7 @@ func TestEthersJSCompatibility(t *testing.T) { require.NoError(t, err) // Execute typescript tests to check what happens with a pruned block. - cmd = exec.Command("npm", "run", "test", "--networkaddr="+network[0].Node.HTTPEndpoint(), "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "block with pruned") + cmd = exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "block with pruned") cmd.Dir = "../ethersjs-api-check/" println("executing mocha test with", cmd.String()) output, err = cmd.CombinedOutput() From 2bdc31e6c55dad40feafb6509724b79ed5eb6866 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 21 Sep 2022 17:05:16 +0100 Subject: [PATCH 17/27] Update log message for clarity --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b650766338..5087586d65 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -758,7 +758,7 @@ func addEthCompatibilityFields(ctx context.Context, block map[string]interface{} // base fee is returned we want to add it as a field and if there was an // error and nil base fee we log the failure. if err != nil && baseFee == nil { - log.Debug("Not adding gasPriceMinimum to RPC response, failed to retrieve gas price minimum", "block", header.Number.Uint64(), "err", err) + log.Debug("Not adding baseFeePerGas to RPC response, failed to retrieve gas price minimum", "block", header.Number.Uint64(), "err", err) return } block["baseFeePerGas"] = (*hexutil.Big)(baseFee) From b354bc4b665513d1202ad3ed73859271e43064e0 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Wed, 21 Sep 2022 17:13:08 +0100 Subject: [PATCH 18/27] Update node-golang dockerfile Add installed go binaries location to user's path --- .circleci/node-golang-dockerfile/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/node-golang-dockerfile/Dockerfile b/.circleci/node-golang-dockerfile/Dockerfile index 3039e7bae1..5b00d4a1d0 100644 --- a/.circleci/node-golang-dockerfile/Dockerfile +++ b/.circleci/node-golang-dockerfile/Dockerfile @@ -3,4 +3,5 @@ FROM circleci/node:12 COPY --from=circleci/golang:1.17.5 /usr/local/go/ /usr/local/go/ +ENV PATH="/home/circleci/go/bin:${PATH}" ENV PATH="/usr/local/go/bin:${PATH}" From 5fd28ff3532430091f18a932100dae3a13c26a30 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Thu, 22 Sep 2022 16:18:10 +0100 Subject: [PATCH 19/27] Update readme to specify a minimum go version This should mitigate the readme going out of date whenever we update go. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 489563b77f..64c93e583a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Most functionality of this client is similar to `go-ethereum`, also known as `ge ## Building the source -Building `geth` requires both a Go (version 1.16) and a C compiler. +Building `geth` requires both Go (min version 1.15) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell From e4e0216dce633c117cf6e6833169db434681c4bc Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Thu, 22 Sep 2022 16:37:19 +0100 Subject: [PATCH 20/27] Default to single quotes in typescript --- ethersjs-api-check/test/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethersjs-api-check/test/test.ts b/ethersjs-api-check/test/test.ts index 3b578ec342..0ae7b6d994 100644 --- a/ethersjs-api-check/test/test.ts +++ b/ethersjs-api-check/test/test.ts @@ -1,4 +1,4 @@ -import {ethers} from "ethers"; +import {ethers} from 'ethers'; import {assert} from 'chai'; import 'mocha'; From 0195beccb2e0563102f7065e3c595f925d39b5dd Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Mon, 26 Sep 2022 11:20:34 +0100 Subject: [PATCH 21/27] Flag to disable RPC compatibilty fields If the flag is set then the 'gasLimit' and 'baseFeePerGas' fields will not be returned on RPC blocks. --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 9 ++++++++ e2e_test/e2e_test.go | 43 ++++++++++++++++++++++++++++++++++++++ eth/api_backend.go | 4 ++++ eth/ethconfig/config.go | 5 +++++ internal/ethapi/api.go | 6 ++++-- internal/ethapi/backend.go | 1 + les/api_backend.go | 4 ++++ test/node.go | 11 +++++----- 9 files changed, 77 insertions(+), 7 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 4dd88cc23a..f9eed133e4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -164,6 +164,7 @@ var ( } rpcFlags = []cli.Flag{ + utils.DisableRPCETHCompatibility, utils.HTTPEnabledFlag, utils.HTTPListenAddrFlag, utils.HTTPPortFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7b98eb5dda..24fce63abe 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -465,6 +465,10 @@ var ( Usage: "Disables db compaction after import", } // RPC settings + DisableRPCETHCompatibility = cli.BoolFlag{ + Name: "disablerpcethcompatibility", + Usage: "If set, blocks returned from the RPC api will not contain the 'gasLimit' and 'baseFeePerGas' fields, which were added to the RPC block representation in order to improve compatibility with ethereum tooling. Note these fields do not currently exist on the internal block representation so they should be disregarded for the purposes of hashing or signing", + } IPCDisabledFlag = cli.BoolFlag{ Name: "ipcdisable", @@ -1762,6 +1766,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name) } + cfg.RPCEthCompatibility = true + if ctx.GlobalIsSet(DisableRPCETHCompatibility.Name) { + cfg.RPCEthCompatibility = false + } + // Disable DNS discovery by default (by using the flag's value even if it hasn't been set and so // has the default value ""), since we don't have DNS discovery set up for Celo. // Note that passing --discovery.dns "" is the way the Geth docs specify for disabling DNS discovery, diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 209f1ade2a..ac02c0382d 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -502,3 +502,46 @@ func TestEthersJSCompatibility(t *testing.T) { println(string(output)) require.NoError(t, err) } + +// This test checks the functionality of the configuration to enable/disable +// returning the 'gasLimit' and 'baseFeePerGas' fields on RPC blocks. +func TestEthersJSCompatibilityDisable(t *testing.T) { + ac := test.AccountConfig(1, 1) + gc, ec, err := test.BuildConfig(ac) + require.NoError(t, err) + + // Check fields present (compatibility set by default) + network, shutdown, err := test.NewNetwork(ac, gc, ec) + require.NoError(t, err) + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) + defer cancel() + + result := make(map[string]interface{}) + err = network[0].WsClient.GetRPCClient().CallContext(ctx, &result, "eth_getBlockByNumber", "latest", true) + require.NoError(t, err) + + _, ok := result["gasLimit"] + assert.True(t, ok, "gasLimit field should be present on RPC block") + _, ok = result["baseFeePerGas"] + assert.True(t, ok, "baseFeePerGas field should be present on RPC block") + + // Turn of compatibility and check fields are not present + ec.RPCEthCompatibility = false + network, shutdown, err = test.NewNetwork(ac, gc, ec) + require.NoError(t, err) + defer shutdown() + + ctx, cancel = context.WithTimeout(context.Background(), time.Second*20) + defer cancel() + + result = make(map[string]interface{}) + err = network[0].WsClient.GetRPCClient().CallContext(ctx, &result, "eth_getBlockByNumber", "latest", true) + require.NoError(t, err) + + _, ok = result["gasLimit"] + assert.False(t, ok, "gasLimit field should not be present on RPC block") + _, ok = result["baseFeePerGas"] + assert.False(t, ok, "baseFeePerGas field should not be present on RPC block") +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 61ff9b1539..7d46c8a57d 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -375,6 +375,10 @@ func (b *EthAPIBackend) RPCGasCap() uint64 { return b.eth.config.RPCGasCap } +func (b *EthAPIBackend) RPCEthCompatibility() bool { + return b.eth.config.RPCEthCompatibility +} + func (b *EthAPIBackend) RPCTxFeeCap() float64 { return b.eth.config.RPCTxFeeCap } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 3898597f28..c47eb8954b 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -146,6 +146,11 @@ type Config struct { // send-transction variants. The unit is ether. RPCTxFeeCap float64 + // RPCEthCompatibility is used to determine whether the 'gaslimit' end + // 'baseFeePerGas' fields should be added to blocks returned by the RPC + // API. Where true indicates the fields should be added. + RPCEthCompatibility bool + // Checkpoint is a hardcoded checkpoint which can be nil. Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 11a3d2fcd6..e40d85787e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -709,7 +709,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B if block != nil && err == nil { response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) - if err == nil { + if err == nil && s.b.RPCEthCompatibility() { addEthCompatibilityFields(ctx, response, s.b, block.Header()) if number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields @@ -732,7 +732,9 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha if err != nil { return nil, err } - addEthCompatibilityFields(ctx, result, s.b, block.Header()) + if s.b.RPCEthCompatibility() { + addEthCompatibilityFields(ctx, result, s.b, block.Header()) + } return result, nil } return nil, err diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index a9976b25fa..b81f73eb5a 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -52,6 +52,7 @@ type Backend interface { RPCGasInflationRate() float64 // global multiplier applied to the gas estimations RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs + RPCEthCompatibility() bool // determines if the fields 'gasLimit' and 'baseFeePerGas' should be returned by the RPC API. UnprotectedAllowed() bool // allows only for EIP155 transactions. // Blockchain API diff --git a/les/api_backend.go b/les/api_backend.go index 9f0586637b..41fbf691b2 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -350,6 +350,10 @@ func (b *LesApiBackend) RPCTxFeeCap() float64 { return b.eth.config.RPCTxFeeCap } +func (b *LesApiBackend) RPCEthCompatibility() bool { + return b.eth.config.RPCEthCompatibility +} + func (b *LesApiBackend) BloomStatus() (uint64, uint64) { if b.eth.bloomIndexer == nil { return 0, 0 diff --git a/test/node.go b/test/node.go index edcf417c1e..f7f8c9a1dd 100644 --- a/test/node.go +++ b/test/node.go @@ -59,11 +59,12 @@ var ( } baseEthConfig = ð.Config{ - SyncMode: downloader.FullSync, - MinSyncPeers: 1, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + SyncMode: downloader.FullSync, + MinSyncPeers: 1, + DatabaseCache: 256, + DatabaseHandles: 256, + TxPool: core.DefaultTxPoolConfig, + RPCEthCompatibility: true, Istanbul: istanbul.Config{ Validator: true, // Set announce gossip period to 1 minute, if not set this results From 99b97501aa951148c7884cc0fc6cbd4a1122f62a Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 27 Sep 2022 16:28:10 +0100 Subject: [PATCH 22/27] Split the tests under 2 describe headings One for tests with state one for tests without. This makes executing each batch of tests easier because we can just grep for the describe headings. --- e2e_test/e2e_test.go | 4 ++-- ethersjs-api-check/test/test.ts | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 881d5e4d3a..6e12d8e5f2 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -491,7 +491,7 @@ func TestEthersJSCompatibility(t *testing.T) { // The tests don't seem to work on CI with IPV6 addresses so we convert to IPV4 here addr := strings.Replace(network[0].Node.HTTPEndpoint(), "[::]", "127.0.0.1", 1) - cmd := exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--invert", "--grep", "block with pruned") + cmd := exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "ethers.js compatibility tests with state") cmd.Dir = "../ethersjs-api-check/" println("executing mocha test with", cmd.String()) output, err := cmd.CombinedOutput() @@ -507,7 +507,7 @@ func TestEthersJSCompatibility(t *testing.T) { require.NoError(t, err) // Execute typescript tests to check what happens with a pruned block. - cmd = exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "block with pruned") + cmd = exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "ethers.js compatibility tests with no state") cmd.Dir = "../ethersjs-api-check/" println("executing mocha test with", cmd.String()) output, err = cmd.CombinedOutput() diff --git a/ethersjs-api-check/test/test.ts b/ethersjs-api-check/test/test.ts index 0ae7b6d994..682cf4919f 100644 --- a/ethersjs-api-check/test/test.ts +++ b/ethersjs-api-check/test/test.ts @@ -2,7 +2,7 @@ import {ethers} from 'ethers'; import {assert} from 'chai'; import 'mocha'; -describe('ethers.js compatibility', () => { +describe('ethers.js compatibility tests with state', () => { it('block retrieved with gasLimit', async () => { let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); @@ -29,6 +29,10 @@ describe('ethers.js compatibility', () => { assert.notEqual(feeData.lastBaseFeePerGas, null); }); +}); + +describe('ethers.js compatibility tests with no state', () => { + // Our blockchain client implementation returns a default gas limit when the // actual gas limit cannot be retrieved. We cannot check fee data against a // pruned block because getFeeData always requests the latest block. @@ -41,4 +45,6 @@ describe('ethers.js compatibility', () => { assert.notEqual(block.gasLimit, null); }); + }); + From 0fa53096e86b3ba84b17fe0dcd95c3e872e86a3b Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 27 Sep 2022 16:28:33 +0100 Subject: [PATCH 23/27] Document that js tests shoudn't be run standalone --- ethersjs-api-check/test/test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethersjs-api-check/test/test.ts b/ethersjs-api-check/test/test.ts index 682cf4919f..18f7ff74a4 100644 --- a/ethersjs-api-check/test/test.ts +++ b/ethersjs-api-check/test/test.ts @@ -1,3 +1,8 @@ +/* + * Note these tests are intended to be invoked only by our e2e tests, they + * should not be executed in a standalone fashion. + * See e2e_test.TestEthersJSCompatibility + */ import {ethers} from 'ethers'; import {assert} from 'chai'; import 'mocha'; From af4224f1e33d9f8cba41226d00aa2be9bdda881d Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 27 Sep 2022 16:33:38 +0100 Subject: [PATCH 24/27] Move ethersjs test project under e2e_test Just to further signify that it is not for standalone use. --- Makefile | 6 +++--- e2e_test/e2e_test.go | 4 ++-- .../ethersjs-api-check}/.gitignore | 0 .../ethersjs-api-check}/package-lock.json | 0 .../ethersjs-api-check}/package.json | 0 .../ethersjs-api-check}/test/test.ts | 0 .../ethersjs-api-check}/tsconfig.json | 0 7 files changed, 5 insertions(+), 5 deletions(-) rename {ethersjs-api-check => e2e_test/ethersjs-api-check}/.gitignore (100%) rename {ethersjs-api-check => e2e_test/ethersjs-api-check}/package-lock.json (100%) rename {ethersjs-api-check => e2e_test/ethersjs-api-check}/package.json (100%) rename {ethersjs-api-check => e2e_test/ethersjs-api-check}/test/test.ts (100%) rename {ethersjs-api-check => e2e_test/ethersjs-api-check}/tsconfig.json (100%) diff --git a/Makefile b/Makefile index 60e649ea57..04eef3f2f2 100644 --- a/Makefile +++ b/Makefile @@ -47,10 +47,10 @@ geth: prepare: prepare-system-contracts prepare-ethersjs-project -prepare-ethersjs-project: ./ethersjs-api-check/node_modules +prepare-ethersjs-project: ./e2e_test/ethersjs-api-check/node_modules -./ethersjs-api-check/node_modules: ./ethersjs-api-check/package.json ./ethersjs-api-check/package-lock.json - @cd ./ethersjs-api-check && npm ci +./e2e_test/ethersjs-api-check/node_modules: ./e2e_test/ethersjs-api-check/package.json ./e2e_test/ethersjs-api-check/package-lock.json + @cd ./e2e_test/ethersjs-api-check && npm ci # This rule checks out celo-monorepo under MONOREPO_PATH at the commit contained in # monorepo_commit and compiles the system solidity contracts. It then copies the diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 6e12d8e5f2..2282cd4cdf 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -492,7 +492,7 @@ func TestEthersJSCompatibility(t *testing.T) { addr := strings.Replace(network[0].Node.HTTPEndpoint(), "[::]", "127.0.0.1", 1) cmd := exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "ethers.js compatibility tests with state") - cmd.Dir = "../ethersjs-api-check/" + cmd.Dir = "./ethersjs-api-check/" println("executing mocha test with", cmd.String()) output, err := cmd.CombinedOutput() println(string(output)) @@ -508,7 +508,7 @@ func TestEthersJSCompatibility(t *testing.T) { // Execute typescript tests to check what happens with a pruned block. cmd = exec.Command("npm", "run", "test", "--networkaddr="+addr, "--blocknum="+hexutil.Uint64(num).String(), "--", "--grep", "ethers.js compatibility tests with no state") - cmd.Dir = "../ethersjs-api-check/" + cmd.Dir = "./ethersjs-api-check/" println("executing mocha test with", cmd.String()) output, err = cmd.CombinedOutput() println(string(output)) diff --git a/ethersjs-api-check/.gitignore b/e2e_test/ethersjs-api-check/.gitignore similarity index 100% rename from ethersjs-api-check/.gitignore rename to e2e_test/ethersjs-api-check/.gitignore diff --git a/ethersjs-api-check/package-lock.json b/e2e_test/ethersjs-api-check/package-lock.json similarity index 100% rename from ethersjs-api-check/package-lock.json rename to e2e_test/ethersjs-api-check/package-lock.json diff --git a/ethersjs-api-check/package.json b/e2e_test/ethersjs-api-check/package.json similarity index 100% rename from ethersjs-api-check/package.json rename to e2e_test/ethersjs-api-check/package.json diff --git a/ethersjs-api-check/test/test.ts b/e2e_test/ethersjs-api-check/test/test.ts similarity index 100% rename from ethersjs-api-check/test/test.ts rename to e2e_test/ethersjs-api-check/test/test.ts diff --git a/ethersjs-api-check/tsconfig.json b/e2e_test/ethersjs-api-check/tsconfig.json similarity index 100% rename from ethersjs-api-check/tsconfig.json rename to e2e_test/ethersjs-api-check/tsconfig.json From 419c504fb38b0c56073cdf2160bbdeba58aee9b8 Mon Sep 17 00:00:00 2001 From: Piers Powlesland Date: Tue, 27 Sep 2022 18:35:36 +0100 Subject: [PATCH 25/27] Do not return block fields that cant be retreived If the state is missing for gasLimit or baseFeePerGas or if there is some other failure when retrieving them then do not add them as fields to the block. Preivously in some cases a default value would have been added to the block and returned. --- .../blockchain_parameters.go | 6 +- .../blockchain_parameters_test.go | 6 +- .../gasprice_minimum/gasprice_minimum.go | 27 +++++++++ e2e_test/ethersjs-api-check/test/test.ts | 59 +++++++++++++++---- e2e_test/ethersjs-api-check/tsconfig.json | 5 +- eth/api_backend.go | 24 ++++++++ internal/ethapi/api.go | 21 ++++--- internal/ethapi/backend.go | 10 ++++ les/api_backend.go | 21 +++++++ rpc/celo_additions.go | 16 +++++ 10 files changed, 166 insertions(+), 29 deletions(-) create mode 100644 rpc/celo_additions.go diff --git a/contracts/blockchain_parameters/blockchain_parameters.go b/contracts/blockchain_parameters/blockchain_parameters.go index 6d113b2022..d8b355d44a 100644 --- a/contracts/blockchain_parameters/blockchain_parameters.go +++ b/contracts/blockchain_parameters/blockchain_parameters.go @@ -79,7 +79,7 @@ func getIntrinsicGasForAlternativeFeeCurrency(vmRunner vm.EVMRunner) (uint64, er // GetBlockGasLimitOrDefault retrieves the block max gas limit // In case of error, it returns the default value func GetBlockGasLimitOrDefault(vmRunner vm.EVMRunner) uint64 { - val, err := getBlockGasLimit(vmRunner) + val, err := GetBlockGasLimit(vmRunner) if err != nil { logError("blockGasLimit", err) return params.DefaultGasLimit @@ -87,8 +87,8 @@ func GetBlockGasLimitOrDefault(vmRunner vm.EVMRunner) uint64 { return val } -// getBlockGasLimit retrieves the block max gas limit -func getBlockGasLimit(vmRunner vm.EVMRunner) (uint64, error) { +// GetBlockGasLimit retrieves the block max gas limit +func GetBlockGasLimit(vmRunner vm.EVMRunner) (uint64, error) { var gasLimit *big.Int err := blockGasLimitMethod.Query(vmRunner, &gasLimit) if err != nil { diff --git a/contracts/blockchain_parameters/blockchain_parameters_test.go b/contracts/blockchain_parameters/blockchain_parameters_test.go index bf4d6602bb..52ccd8d5de 100644 --- a/contracts/blockchain_parameters/blockchain_parameters_test.go +++ b/contracts/blockchain_parameters/blockchain_parameters_test.go @@ -71,8 +71,8 @@ func TestGetIntrinsicGasForAlternativeFeeCurrencyOrDefault(t *testing.T) { } func TestGetBlockGasLimit(t *testing.T) { - testutil.TestFailOnFailingRunner(t, getBlockGasLimit) - testutil.TestFailsWhenContractNotDeployed(t, contracts.ErrSmartContractNotDeployed, getBlockGasLimit) + testutil.TestFailOnFailingRunner(t, GetBlockGasLimit) + testutil.TestFailsWhenContractNotDeployed(t, contracts.ErrSmartContractNotDeployed, GetBlockGasLimit) t.Run("should return block gas limit", func(t *testing.T) { g := NewGomegaWithT(t) @@ -84,7 +84,7 @@ func TestGetBlockGasLimit(t *testing.T) { }, ) - gas, err := getBlockGasLimit(runner) + gas, err := GetBlockGasLimit(runner) g.Expect(err).ToNot(HaveOccurred()) g.Expect(gas).To(Equal(uint64(50000))) }) diff --git a/contracts/gasprice_minimum/gasprice_minimum.go b/contracts/gasprice_minimum/gasprice_minimum.go index e6b40915ee..c082395b26 100644 --- a/contracts/gasprice_minimum/gasprice_minimum.go +++ b/contracts/gasprice_minimum/gasprice_minimum.go @@ -17,6 +17,7 @@ package gasprice_minimum import ( + "fmt" "math/big" "github.com/celo-org/celo-blockchain/common" @@ -89,6 +90,32 @@ func GetGasPriceMinimum(vmRunner vm.EVMRunner, currency *common.Address) (*big.I return gasPriceMinimum, err } +// GetRealGasPriceMinimum is similar to GetRealGasPriceMinimum but if there is +// a problem retrieving the gas price minimum it will return the error and a +// nil gas price minimum. +func GetRealGasPriceMinimum(vmRunner vm.EVMRunner, currency *common.Address) (*big.Int, error) { + var currencyAddress common.Address + var err error + + if currency == nil { + currencyAddress, err = contracts.GetRegisteredAddress(vmRunner, params.GoldTokenRegistryId) + + if err != nil { + return nil, fmt.Errorf("failed to retrieve gold token address: %w", err) + } + } else { + currencyAddress = *currency + } + + var gasPriceMinimum *big.Int + err = getGasPriceMinimumMethod.Query(vmRunner, &gasPriceMinimum, currencyAddress) + if err != nil { + return nil, fmt.Errorf("failed to retrieve gas price minimum for currency %v, error: %w", currencyAddress.String(), err) + } + + return gasPriceMinimum, nil +} + func GetGasPriceMinimumFloor(vmRunner vm.EVMRunner) (*big.Int, error) { var err error diff --git a/e2e_test/ethersjs-api-check/test/test.ts b/e2e_test/ethersjs-api-check/test/test.ts index 18f7ff74a4..4baa4d67d3 100644 --- a/e2e_test/ethersjs-api-check/test/test.ts +++ b/e2e_test/ethersjs-api-check/test/test.ts @@ -9,7 +9,7 @@ import 'mocha'; describe('ethers.js compatibility tests with state', () => { - it('block retrieved with gasLimit', async () => { + it('provider.getBlock works (block has gasLimit set)', async () => { let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); let block = await provider.getBlock(process.env.npm_config_blocknum as string); @@ -18,7 +18,7 @@ describe('ethers.js compatibility tests with state', () => { assert.notEqual(block.gasLimit, null); }); - it('EIP-1559 transactions supported', async () => { + it('EIP-1559 transactions supported (can get feeData)', async () => { let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); // The fee data is the construct used to determine if EIP-1559 transactions are supported, if it contains max @@ -34,22 +34,61 @@ describe('ethers.js compatibility tests with state', () => { assert.notEqual(feeData.lastBaseFeePerGas, null); }); + it('block has gasLimit', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + const fullBlock = await provider.send( + 'eth_getBlockByNumber', + [ethers.utils.hexValue(process.env.npm_config_blocknum as string), true] + ) + assert.isTrue(fullBlock.hasOwnProperty('gasLimit')) + }); + + it('block has baseFeePerGas', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + const fullBlock = await provider.send( + 'eth_getBlockByNumber', + [ethers.utils.hexValue(process.env.npm_config_blocknum as string), true] + ) + assert.isTrue(fullBlock.hasOwnProperty('baseFeePerGas')) + }); + }); describe('ethers.js compatibility tests with no state', () => { - // Our blockchain client implementation returns a default gas limit when the - // actual gas limit cannot be retrieved. We cannot check fee data against a - // pruned block because getFeeData always requests the latest block. - it('block with pruned state still reports gas limit', async () => { + it('provider.getBlock throws exception (no gasLimit)', async () => { let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); - let block = await provider.getBlock(process.env.npm_config_blocknum as string); + try { + await provider.getBlock(process.env.npm_config_blocknum as string); + } catch (e) { + return + } + assert.fail("Expecting exception to be thrown when getting block") + }); - // These assertions trigger on undefined or null - assert.notEqual(block, null); - assert.notEqual(block.gasLimit, null); + it('block has no gasLimit', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + const fullBlock = await provider.send( + 'eth_getBlockByNumber', + [ethers.utils.hexValue(process.env.npm_config_blocknum as string), true] + ) + assert.isFalse(fullBlock.hasOwnProperty('gasLimit')) + }); + + it('block has no baseFeePerGas', async () => { + let provider = new ethers.providers.JsonRpcProvider(process.env.npm_config_networkaddr); + const fullBlock = await provider.send( + 'eth_getBlockByNumber', + [ethers.utils.hexValue(process.env.npm_config_blocknum as string), true] + ) + assert.isFalse(fullBlock.hasOwnProperty('baseFeePerGas')) }); }); + +// const fullBlock = await provider.send( +// 'eth_getBlockByNumber', +// [ethers.utils.hexValue(blockNumber), true] +// ) diff --git a/e2e_test/ethersjs-api-check/tsconfig.json b/e2e_test/ethersjs-api-check/tsconfig.json index 9b2743b765..1f56fffaaa 100644 --- a/e2e_test/ethersjs-api-check/tsconfig.json +++ b/e2e_test/ethersjs-api-check/tsconfig.json @@ -4,8 +4,9 @@ "module": "commonjs", "esModuleInterop": true, "strict": true, - "rootDir": "src", + "rootDir": ".", "outDir": "dist", - "moduleResolution": "node" + "moduleResolution": "node", + "useUnknownInCatchVariables": true } } diff --git a/eth/api_backend.go b/eth/api_backend.go index 7d46c8a57d..49be526066 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -19,6 +19,7 @@ package eth import ( "context" "errors" + "fmt" "math/big" ethereum "github.com/celo-org/celo-blockchain" @@ -315,6 +316,15 @@ func (b *EthAPIBackend) GasPriceMinimumForHeader(ctx context.Context, currencyAd return gpm.GetGasPriceMinimum(vmRunner, currencyAddress) } +func (b *EthAPIBackend) RealGasPriceMinimumForHeader(ctx context.Context, currencyAddress *common.Address, header *types.Header) (*big.Int, error) { + state, err := b.eth.blockchain.StateAt(header.Root) + if err != nil { + return nil, err + } + vmRunner := b.eth.BlockChain().NewEVMRunner(header, state) + return gpm.GetRealGasPriceMinimum(vmRunner, currencyAddress) +} + func (b *EthAPIBackend) SuggestPrice(ctx context.Context, currencyAddress *common.Address) (*big.Int, error) { vmRunner, err := b.eth.BlockChain().NewEVMRunnerForCurrentBlock() if err != nil { @@ -334,6 +344,20 @@ func (b *EthAPIBackend) GetBlockGasLimit(ctx context.Context, blockNrOrHash rpc. return blockchain_parameters.GetBlockGasLimitOrDefault(vmRunner) } +func (b *EthAPIBackend) GetRealBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) { + statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return 0, fmt.Errorf("LesApiBackend failed to retreive state for block gas limit for block %v: %w", blockNrOrHash, err) + } + + caller := b.eth.BlockChain().NewEVMRunner(header, statedb) + limit, err := blockchain_parameters.GetBlockGasLimit(caller) + if err != nil { + return 0, fmt.Errorf("LesApiBackend failed to retreive block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) + } + return limit, nil +} + func (b *EthAPIBackend) NewEVMRunner(header *types.Header, state vm.StateDB) vm.EVMRunner { return b.eth.BlockChain().NewEVMRunner(header, state) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e40d85787e..c75da22012 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -749,21 +749,20 @@ func addEthCompatibilityFields(ctx context.Context, block map[string]interface{} numhash := rpc.BlockNumberOrHash{ BlockHash: &hash, } - gasLimit := b.GetBlockGasLimit(ctx, numhash) - block["gasLimit"] = hexutil.Uint64(gasLimit) + gasLimit, err := b.GetRealBlockGasLimit(ctx, numhash) + if err != nil { + log.Debug("Not adding gasLimit to RPC response, failed to retrieve it", "block", header.Number.Uint64(), "err", err) + } else { + block["gasLimit"] = hexutil.Uint64(gasLimit) + } // Providing nil as the currency address gets the gas price minimum for the native celo asset. - baseFee, err := b.GasPriceMinimumForHeader(ctx, nil, header) - - // GasPriceMinimumForHeader can return an error + non nil baseFee, an error - // and nil base fee or a base fee and a nil error. In all cases where a - // base fee is returned we want to add it as a field and if there was an - // error and nil base fee we log the failure. - if err != nil && baseFee == nil { + baseFee, err := b.RealGasPriceMinimumForHeader(ctx, nil, header) + if err != nil { log.Debug("Not adding baseFeePerGas to RPC response, failed to retrieve gas price minimum", "block", header.Number.Uint64(), "err", err) - return + } else { + block["baseFeePerGas"] = (*hexutil.Big)(baseFee) } - block["baseFeePerGas"] = (*hexutil.Big)(baseFee) } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index b81f73eb5a..d84255d833 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -44,6 +44,11 @@ type Backend interface { SuggestGasTipCap(ctx context.Context, currencyAddress *common.Address) (*big.Int, error) CurrentGasPriceMinimum(ctx context.Context, currencyAddress *common.Address) (*big.Int, error) GasPriceMinimumForHeader(ctx context.Context, currencyAddress *common.Address, header *types.Header) (*big.Int, error) + + // As opposed to GasPriceMinimumForHeader which returns a default value in + // some cases when it can't retrieve the gas price minimum, this function + // returns an error and no gas price minimum when it encounters a problem. + RealGasPriceMinimumForHeader(ctx context.Context, currencyAddress *common.Address, header *types.Header) (*big.Int, error) SyncProgress() ethereum.SyncProgress ChainDb() ethdb.Database @@ -99,6 +104,11 @@ type Backend interface { GatewayFee() *big.Int GetIntrinsicGasForAlternativeFeeCurrency(ctx context.Context) uint64 GetBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) uint64 + + // As opposed to GetBlockGasLimit which returns a default value in the case + // that it can't retrieve the block gas limit, this function returns an + // error and no gas limit when it encounters a problem. + GetRealBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) NewEVMRunner(*types.Header, vm.StateDB) vm.EVMRunner Engine() consensus.Engine } diff --git a/les/api_backend.go b/les/api_backend.go index 41fbf691b2..f98d841770 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -19,6 +19,7 @@ package les import ( "context" "errors" + "fmt" "math/big" ethereum "github.com/celo-org/celo-blockchain" @@ -295,6 +296,20 @@ func (b *LesApiBackend) GetBlockGasLimit(ctx context.Context, blockNrOrHash rpc. return blockchain_parameters.GetBlockGasLimitOrDefault(caller) } +func (b *LesApiBackend) GetRealBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) { + statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return 0, fmt.Errorf("LesApiBackend failed to retreive state for block gas limit for block %v: %w", blockNrOrHash, err) + } + + caller := b.eth.BlockChain().NewEVMRunner(header, statedb) + limit, err := blockchain_parameters.GetBlockGasLimit(caller) + if err != nil { + return 0, fmt.Errorf("LesApiBackend failed to retreive block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) + } + return limit, nil +} + func (b *LesApiBackend) NewEVMRunner(header *types.Header, state vm.StateDB) vm.EVMRunner { return b.eth.BlockChain().NewEVMRunner(header, state) } @@ -322,6 +337,12 @@ func (b *LesApiBackend) GasPriceMinimumForHeader(ctx context.Context, currencyAd return gpm.GetGasPriceMinimum(vmRunner, currencyAddress) } +func (b *LesApiBackend) RealGasPriceMinimumForHeader(ctx context.Context, currencyAddress *common.Address, header *types.Header) (*big.Int, error) { + state := light.NewState(ctx, header, b.eth.odr) + vmRunner := b.eth.blockchain.NewEVMRunner(header, state) + return gpm.GetRealGasPriceMinimum(vmRunner, currencyAddress) +} + func (b *LesApiBackend) ChainDb() ethdb.Database { return b.eth.chainDb } diff --git a/rpc/celo_additions.go b/rpc/celo_additions.go new file mode 100644 index 0000000000..07a5ed56f4 --- /dev/null +++ b/rpc/celo_additions.go @@ -0,0 +1,16 @@ +package rpc + +import ( + "fmt" +) + +func (bnh *BlockNumberOrHash) String() string { + if bnh.BlockHash != nil { + return bnh.BlockHash.String() + } + canonical := "" + if bnh.RequireCanonical { + canonical = " (canonical)" + } + return fmt.Sprintf("%d%s", bnh.BlockNumber, canonical) +} From 986b06c52b0ad24c43a934f506ad06110d1187b8 Mon Sep 17 00:00:00 2001 From: Pasto Date: Tue, 27 Sep 2022 17:24:43 -0300 Subject: [PATCH 26/27] Fix typos --- eth/api_backend.go | 4 ++-- les/api_backend.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 49be526066..66822b2d8b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -347,13 +347,13 @@ func (b *EthAPIBackend) GetBlockGasLimit(ctx context.Context, blockNrOrHash rpc. func (b *EthAPIBackend) GetRealBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) { statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if err != nil { - return 0, fmt.Errorf("LesApiBackend failed to retreive state for block gas limit for block %v: %w", blockNrOrHash, err) + return 0, fmt.Errorf("EthApiBackend failed to retrieve state for block gas limit for block %v: %w", blockNrOrHash, err) } caller := b.eth.BlockChain().NewEVMRunner(header, statedb) limit, err := blockchain_parameters.GetBlockGasLimit(caller) if err != nil { - return 0, fmt.Errorf("LesApiBackend failed to retreive block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) + return 0, fmt.Errorf("EthApiBackend failed to retrieve block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) } return limit, nil } diff --git a/les/api_backend.go b/les/api_backend.go index f98d841770..26791a18da 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -299,13 +299,13 @@ func (b *LesApiBackend) GetBlockGasLimit(ctx context.Context, blockNrOrHash rpc. func (b *LesApiBackend) GetRealBlockGasLimit(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) { statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if err != nil { - return 0, fmt.Errorf("LesApiBackend failed to retreive state for block gas limit for block %v: %w", blockNrOrHash, err) + return 0, fmt.Errorf("LesApiBackend failed to retrieve state for block gas limit for block %v: %w", blockNrOrHash, err) } caller := b.eth.BlockChain().NewEVMRunner(header, statedb) limit, err := blockchain_parameters.GetBlockGasLimit(caller) if err != nil { - return 0, fmt.Errorf("LesApiBackend failed to retreive block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) + return 0, fmt.Errorf("LesApiBackend failed to retrieve block gas limit from blockchain parameters constract for block %v: %w", blockNrOrHash, err) } return limit, nil } From f8dc1ed606ec2986afd3f08b3921034499bf43a5 Mon Sep 17 00:00:00 2001 From: Pasto Date: Tue, 27 Sep 2022 17:56:34 -0300 Subject: [PATCH 27/27] Remove unused code --- e2e_test/ethersjs-api-check/test/test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/e2e_test/ethersjs-api-check/test/test.ts b/e2e_test/ethersjs-api-check/test/test.ts index 4baa4d67d3..77e7aeee33 100644 --- a/e2e_test/ethersjs-api-check/test/test.ts +++ b/e2e_test/ethersjs-api-check/test/test.ts @@ -86,9 +86,3 @@ describe('ethers.js compatibility tests with no state', () => { }); - - -// const fullBlock = await provider.send( -// 'eth_getBlockByNumber', -// [ethers.utils.hexValue(blockNumber), true] -// )