From 385e732e384c1191e4dfc3ef2bbc535dbb7b12b0 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Tue, 19 Sep 2023 22:34:26 +1200 Subject: [PATCH 1/9] Use common place for our well-known asset ids --- examples/substrate/use-feeProxy/src/callBatchAll.ts | 4 +--- examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts | 4 +--- examples/substrate/use-feeProxy/src/callSystemRemark.ts | 4 +--- packages/utils/src/porcini-assets.ts | 4 ++++ 4 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 packages/utils/src/porcini-assets.ts diff --git a/examples/substrate/use-feeProxy/src/callBatchAll.ts b/examples/substrate/use-feeProxy/src/callBatchAll.ts index bb41e51..9b5aa86 100644 --- a/examples/substrate/use-feeProxy/src/callBatchAll.ts +++ b/examples/substrate/use-feeProxy/src/callBatchAll.ts @@ -1,12 +1,10 @@ import { ALICE, BOB, CHARLIE } from "@trne/utils/accounts"; import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents"; import { formatEventData } from "@trne/utils/formatEventData"; +import { ASTO_ASSET_ID, XRP_ASSET_ID } from "@trne/utils/porcini-assets"; import { sendExtrinsic } from "@trne/utils/sendExtrinsic"; import { withChainApi } from "@trne/utils/withChainApi"; -const ASTO_ASSET_ID = 17_508; -const XRP_ASSET_ID = 2; - interface AmountsIn { Ok: [number, number]; } diff --git a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts index 2ac15ea..aa23c2c 100644 --- a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts +++ b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts @@ -1,12 +1,10 @@ import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents"; import { formatEventData } from "@trne/utils/formatEventData"; +import { ASTO_ASSET_ID, XRP_ASSET_ID } from "@trne/utils/porcini-assets"; import { sendExtrinsic } from "@trne/utils/sendExtrinsic"; import { withChainApi } from "@trne/utils/withChainApi"; import assert from "assert"; -const ASTO_ASSET_ID = 17_508; -const XRP_ASSET_ID = 2; - interface AmountsIn { Ok: [number, number]; } diff --git a/examples/substrate/use-feeProxy/src/callSystemRemark.ts b/examples/substrate/use-feeProxy/src/callSystemRemark.ts index b3da827..82c69f4 100644 --- a/examples/substrate/use-feeProxy/src/callSystemRemark.ts +++ b/examples/substrate/use-feeProxy/src/callSystemRemark.ts @@ -1,11 +1,9 @@ import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents"; import { formatEventData } from "@trne/utils/formatEventData"; +import { ASTO_ASSET_ID, XRP_ASSET_ID } from "@trne/utils/porcini-assets"; import { sendExtrinsic } from "@trne/utils/sendExtrinsic"; import { withChainApi } from "@trne/utils/withChainApi"; -const ASTO_ASSET_ID = 17_508; -const XRP_ASSET_ID = 2; - interface AmountsIn { Ok: [number, number]; } diff --git a/packages/utils/src/porcini-assets.ts b/packages/utils/src/porcini-assets.ts new file mode 100644 index 0000000..233989e --- /dev/null +++ b/packages/utils/src/porcini-assets.ts @@ -0,0 +1,4 @@ +// asset ids on Porcini testnet +export const SYLO_ASSET_ID = 3_172; +export const ASTO_ASSET_ID = 17_508; +export const XRP_ASSET_ID = 2; From 412e43ac443bdc54d4d7e2ba4f4d39ece670e268 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Wed, 20 Sep 2023 10:27:03 +1200 Subject: [PATCH 2/9] Update comments --- examples/substrate/use-feeProxy/src/callBatchAll.ts | 2 +- examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts | 2 +- examples/substrate/use-feeProxy/src/callSystemRemark.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/substrate/use-feeProxy/src/callBatchAll.ts b/examples/substrate/use-feeProxy/src/callBatchAll.ts index 9b5aa86..19e8cf4 100644 --- a/examples/substrate/use-feeProxy/src/callBatchAll.ts +++ b/examples/substrate/use-feeProxy/src/callBatchAll.ts @@ -30,7 +30,7 @@ withChainApi("porcini", async (api, caller) => { const paymentInfo = await batchAllCall.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); - // querying the dex for swap price, to determine the `maxPayment` you are willing to pay + // query the the `dex` to determine the `maxPayment` you are willing to pay const { Ok: [amountIn], } = (await api.rpc.dex.getAmountsIn(estimatedFee, [ diff --git a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts index aa23c2c..5945383 100644 --- a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts +++ b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts @@ -32,7 +32,7 @@ withChainApi("porcini", async (api, caller) => { const paymentInfo = await remarkCall.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); - // querying the dex for swap price, to determine the `maxPayment` you are willing to pay in ASTO + // query the the `dex` to determine the `maxPayment` you are willing to pay const { Ok: [amountIn], } = (await api.rpc.dex.getAmountsIn(estimatedFee, [ diff --git a/examples/substrate/use-feeProxy/src/callSystemRemark.ts b/examples/substrate/use-feeProxy/src/callSystemRemark.ts index 82c69f4..b0513a5 100644 --- a/examples/substrate/use-feeProxy/src/callSystemRemark.ts +++ b/examples/substrate/use-feeProxy/src/callSystemRemark.ts @@ -20,7 +20,7 @@ withChainApi("porcini", async (api, caller) => { const paymentInfo = await remarkCall.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); - // querying the dex for swap price, to determine the `maxPayment` you are willing to pay + // query the the `dex` to determine the `maxPayment` you are willing to pay const { Ok: [amountIn], } = (await api.rpc.dex.getAmountsIn(estimatedFee, [ From fa7d29de0114363678f97756964106fcad4143d9 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Wed, 20 Sep 2023 14:04:53 +1200 Subject: [PATCH 3/9] Update `evm/use-feeProxy` example with proper maxPayment and maxFeePerGas calc --- examples/evm/use-feeProxy/README.md | 58 +--- examples/evm/use-feeProxy/package.json | 8 +- .../evm/use-feeProxy/src/callERC20Transfer.ts | 67 ++++ .../src/callWithFeePreferences.ts | 64 ---- package.json | 1 - packages/utils/package.json | 7 +- packages/utils/src/filterTransactionEvents.ts | 16 + packages/utils/src/getERC20Contract.ts | 8 + packages/utils/src/getFeeProxyContract.ts | 6 + packages/utils/src/getFeeProxyPricePair.ts | 38 +++ packages/utils/src/getLogger.ts | 11 + packages/utils/src/withEthersProvider.ts | 34 ++ pnpm-lock.yaml | 297 ++++++++++++++---- 13 files changed, 432 insertions(+), 183 deletions(-) create mode 100644 examples/evm/use-feeProxy/src/callERC20Transfer.ts delete mode 100644 examples/evm/use-feeProxy/src/callWithFeePreferences.ts create mode 100644 packages/utils/src/filterTransactionEvents.ts create mode 100644 packages/utils/src/getERC20Contract.ts create mode 100644 packages/utils/src/getFeeProxyContract.ts create mode 100644 packages/utils/src/getFeeProxyPricePair.ts create mode 100644 packages/utils/src/getLogger.ts create mode 100644 packages/utils/src/withEthersProvider.ts diff --git a/examples/evm/use-feeProxy/README.md b/examples/evm/use-feeProxy/README.md index 7ff6241..7eaf82e 100644 --- a/examples/evm/use-feeProxy/README.md +++ b/examples/evm/use-feeProxy/README.md @@ -1,52 +1,22 @@ -# Use FeeProxy +# FeeProxy Precompile -First run +[![Run in StackBlitz](https://img.shields.io/badge/Open_in_StackBlitz-1269D3?style=for-the-badge&logo=stackblitz&logoColor=white)](https://stackblitz.com/github/futureversecom/trn-examples?file=examples%2Fevm%2Fuse-feeProxy%2FREADME.md&title=FeeProxy%20Precompile%20Examples) [![Precompile Documentation](https://img.shields.io/badge/Pallet_Documentation-black?style=for-the-badge&logo=googledocs&logoColor=white)](https://docs-beta.therootnetwork.com/buidl/evm/precompile-feeProxy) -``` -export CALLER_PRIVATE_KEY=0x000... -``` - -## Contract Read/Write +> [!IMPORTANT] +> Ensure the following ENV vars are available before running the examples +> +> - `CALLER_PRIVATE_KEY` - Private key of an account that submits the transaction. Follow this guide to [create and fund an account with some test tokens](../../GUIDES.md) on Porcini (testnet) if you don't have one yet. -Specify the payment asset id to get paymentPrecompileAddress - -```js -const { erc20Precompile, wallet } = getERC20PrecompileForAssetId( - env.CALLER_PRIVATE_KEY, - paymentAsset -); -const feeToken = erc20Precompile; -``` - -Create FeeToken contract - -``` -const feeProxy = new Contract(FEE_PROXY_ADDRESS, FEE_PROXY_ABI, wallet); -``` +## Examples -### `callWithFeePreferences(address asset, uint128 maxPayment, address target, bytes input)` +```bash +# change your working directory to this example first +cd examples/evm/use-feeProxy -- `asset` - precompile address for payment asset -- `maxPayment` - max payment user is willing to be pay in payment asset -- `target` - precompile address for payment asset -- `input` - transaction for which fee is to be paid in payment asset +# export all required environments +export CALLER_PRIVATE_KEY= -```js -const unsignedTx = { - type: 0, - from: wallet.address, - to: FEE_PROXY_ADDRESS, - nonce: nonce, - data: feeProxy.interface.encodeFunctionData("callWithFeePreferences", [ - feeToken.address, - maxFeePaymentInToken, - feeToken.address, - transferInput, - ]), - gasLimit: gasEstimate, - gasPrice: fees.gasPrice, -}; +# `feeProxy.callWithFeePreferences` that wraps around `ERC20.transfer` +pnpm call:callERC20Transfer -await wallet.signTransaction(unsignedTx); -const tx = await wallet.sendTransaction(unsignedTx); ``` diff --git a/examples/evm/use-feeProxy/package.json b/examples/evm/use-feeProxy/package.json index b2eb5e6..db76e38 100644 --- a/examples/evm/use-feeProxy/package.json +++ b/examples/evm/use-feeProxy/package.json @@ -1,10 +1,6 @@ { "scripts": { - "call": "ts-node --project ../../../tsconfig.json" - }, - "eslintConfig": { - "rules": { - "@typescript-eslint/no-explicit-any": "off" - } + "call": "ts-node --project ../../../tsconfig.json", + "call:callERC20Transfer": "pnpm call src/callERC20Transfer.ts" } } diff --git a/examples/evm/use-feeProxy/src/callERC20Transfer.ts b/examples/evm/use-feeProxy/src/callERC20Transfer.ts new file mode 100644 index 0000000..eee5924 --- /dev/null +++ b/examples/evm/use-feeProxy/src/callERC20Transfer.ts @@ -0,0 +1,67 @@ +import { ALICE } from "@trne/utils/accounts"; +import { filterTransactionEvents } from "@trne/utils/filterTransactionEvents"; +import { getERC20Contract } from "@trne/utils/getERC20Contract"; +import { ERC20_ABI } from "@trne/utils/getERC20PrecompileAddress"; +import { getFeeProxyContract } from "@trne/utils/getFeeProxyContract"; +import { getFeeProxyPricePair } from "@trne/utils/getFeeProxyPricePair"; +import { ASTO_ASSET_ID, SYLO_ASSET_ID } from "@trne/utils/porcini-assets"; +import { withEthersProvider } from "@trne/utils/withEthersProvider"; +import { ContractReceipt, utils } from "ethers"; + +/** + * Use `feeProxy.callWithFeePreferences` to trigger a `transfer` call of SYLO token, and pay gas + * in ASTO token. + * + * Assumes the caller has some ASTO balance. + */ +withEthersProvider("porcini", async (provider, wallet, logger) => { + // contracts creation + const feeProxy = getFeeProxyContract().connect(wallet); + const sylo = getERC20Contract(SYLO_ASSET_ID).connect(wallet); + const asto = getERC20Contract(ASTO_ASSET_ID).connect(wallet); + + // transfer call + const transferAmount = utils.parseUnits("1.0", 18); // 1 SYLO + const transferInput = new utils.Interface(ERC20_ABI).encodeFunctionData("transfer", [ + ALICE, + transferAmount, + ]); + const transferEstimate = await sylo.estimateGas.transfer(ALICE, transferAmount); + + logger.info( + `prepare a transfer call with destination="${ALICE}", amount="${transferAmount}", and estimateGas="${transferEstimate}"` + ); + + // retrieve the maxPayment and maxFeePerGas parameters with slippage to be 0.05 (5%) + const { maxPayment, maxFeePerGas } = await getFeeProxyPricePair( + provider, + transferEstimate, + ASTO_ASSET_ID, + 0.05 + ); + + logger.info( + `dispatch a feeProxy call with maxPayment="${maxPayment}", and maxFeePerGas="${maxFeePerGas}"` + ); + + const tx = await feeProxy.callWithFeePreferences( + asto.address, + maxPayment, + sylo.address, + transferInput, + { + gasLimit: transferEstimate, + maxFeePerGas: maxFeePerGas, + maxPriorityFeePerGas: 0, + } + ); + + const receipt = (await tx.wait()) as unknown as ContractReceipt; + + const [transferEvent] = filterTransactionEvents(ERC20_ABI, receipt.logs, ["Transfer"]); + + logger.info( + { transferEvent: { name: transferEvent.name, args: transferEvent.args } }, + "receive event" + ); +}); diff --git a/examples/evm/use-feeProxy/src/callWithFeePreferences.ts b/examples/evm/use-feeProxy/src/callWithFeePreferences.ts deleted file mode 100644 index fa95fb1..0000000 --- a/examples/evm/use-feeProxy/src/callWithFeePreferences.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { collectArgs } from "@trne/utils/collectArgs"; -import { ERC20_ABI, getERC20PrecompileForAssetId } from "@trne/utils/getERC20PrecompileAddress"; -import { getEthersProvider } from "@trne/utils/getEthersProvider"; -import assert from "assert"; -import { cleanEnv, str } from "envalid"; -import { Contract, utils } from "ethers"; - -const argv = collectArgs(); - -const env = cleanEnv(process.env, { - CALLER_PRIVATE_KEY: str(), // private key of extrinsic caller -}); - -const FEE_PROXY_ADDRESS = "0x00000000000000000000000000000000000004bb"; -export const FEE_PROXY_ABI = [ - "function callWithFeePreferences(address asset, uint128 maxPayment, address target, bytes input)", -]; - -export async function main() { - assert("paymentAsset" in argv, "Payment asset ID is required"); - const provider = getEthersProvider("porcini"); - const fees = await provider.getFeeData(); - const { paymentAsset } = argv as unknown as { paymentAsset: number }; - const destination = "0xE04CC55ebEE1cBCE552f250e85c57B70B2E2625b"; - const { erc20Precompile, wallet } = getERC20PrecompileForAssetId( - env.CALLER_PRIVATE_KEY, - paymentAsset - ); - const feeToken = erc20Precompile; - const transferAmount = 1; - const iface = new utils.Interface(ERC20_ABI); - const transferInput = iface.encodeFunctionData("transfer", [destination, transferAmount]); - const maxFeePaymentInToken = 10000000000; - const feeProxy = new Contract(FEE_PROXY_ADDRESS, FEE_PROXY_ABI, wallet); - const gasLimit = await feeToken.estimateGas.transfer(destination, transferAmount); - const nonce = await wallet.getTransactionCount(); - const data = feeProxy.interface.encodeFunctionData("callWithFeePreferences", [ - feeToken.address, - maxFeePaymentInToken, - feeToken.address, - transferInput, - ]); - const gasPrice = fees.gasPrice!; - const unsignedTx = { - type: 0, - from: wallet.address, - to: FEE_PROXY_ADDRESS, - nonce: nonce, - data, - gasLimit, - gasPrice, - }; - - await wallet.signTransaction(unsignedTx); - const tx = await wallet.sendTransaction(unsignedTx); - const receipt = await tx.wait(); - console.log("receipt:", receipt); - // check updated balances - const tokenBalanceUpdated = await feeToken.balanceOf(wallet.address); - console.log("tokenBalanceUpdated:", tokenBalanceUpdated.toString()); -} - -main(); diff --git a/package.json b/package.json index 3df909f..9cf474e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "dependencies": { "envalid": "^7.3.1", "ethers": "^5.7.2", - "pretty-error": "^4.0.0", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/packages/utils/package.json b/packages/utils/package.json index 3682bb9..a371980 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -6,7 +6,10 @@ "@polkadot/util": "^12.3.2", "@polkadot/util-crypto": "^12.3.2", "@therootnetwork/api": "^1.0.2", - "@therootnetwork/evm": "^1.0.0", - "realm-web": "^2.0.0" + "@therootnetwork/evm": "^1.0.3", + "realm-web": "^2.0.0", + "pino": "^8.15.1", + "pino-pretty": "^10.2.0", + "pretty-error": "^4.0.0" } } diff --git a/packages/utils/src/filterTransactionEvents.ts b/packages/utils/src/filterTransactionEvents.ts new file mode 100644 index 0000000..58b3803 --- /dev/null +++ b/packages/utils/src/filterTransactionEvents.ts @@ -0,0 +1,16 @@ +import { ContractReceipt, utils } from "ethers"; +import assert from "node:assert"; + +export function filterTransactionEvents( + abi: string[], + logs: ContractReceipt["logs"], + eventNames: string[] +) { + const int = new utils.Interface(abi); + + return eventNames.map((eventName) => { + const event = logs.map((log) => int.parseLog(log)).find((event) => event.name === eventName); + assert(event); + return event; + }); +} diff --git a/packages/utils/src/getERC20Contract.ts b/packages/utils/src/getERC20Contract.ts new file mode 100644 index 0000000..1d8baf8 --- /dev/null +++ b/packages/utils/src/getERC20Contract.ts @@ -0,0 +1,8 @@ +import { assetIdToERC20Address, ERC20_ABI } from "@therootnetwork/evm"; +import { Contract } from "ethers"; + +export function getERC20Contract(assetId: number): Contract { + const assetAddress = assetIdToERC20Address(assetId); + + return new Contract(assetAddress, ERC20_ABI); +} diff --git a/packages/utils/src/getFeeProxyContract.ts b/packages/utils/src/getFeeProxyContract.ts new file mode 100644 index 0000000..4496b8b --- /dev/null +++ b/packages/utils/src/getFeeProxyContract.ts @@ -0,0 +1,6 @@ +import { FEE_PROXY_PRECOMPILE_ABI, FEE_PROXY_PRECOMPILE_ADDRESS } from "@therootnetwork/evm"; +import { Contract } from "ethers"; + +export function getFeeProxyContract(): Contract { + return new Contract(FEE_PROXY_PRECOMPILE_ADDRESS, FEE_PROXY_PRECOMPILE_ABI); +} diff --git a/packages/utils/src/getFeeProxyPricePair.ts b/packages/utils/src/getFeeProxyPricePair.ts new file mode 100644 index 0000000..29667c7 --- /dev/null +++ b/packages/utils/src/getFeeProxyPricePair.ts @@ -0,0 +1,38 @@ +import { BigNumber } from "ethers"; +import assert from "node:assert"; + +import { XRP_ASSET_ID } from "./porcini-assets"; +import { EthersProvider } from "./withEthersProvider"; + +interface AmountsIn { + Ok: [number, number]; +} + +export async function getFeeProxyPricePair( + provider: EthersProvider, + gasEstimate: BigNumber, + feeAssetId: number, + slippage = 0 +): Promise<{ maxPayment: BigNumber; maxFeePerGas: BigNumber }> { + const { lastBaseFeePerGas: maxFeePerGas } = await provider.getFeeData(); + + assert(maxFeePerGas); + + // convert gasPrice in ETH to gasPrice in XRP, which has different decimals, one is 18 & one is 6 + const gasPriceInEth = gasEstimate.mul(maxFeePerGas); + const remainder = gasPriceInEth.mod(10 ** 12); + const gasPriceInXRP = gasPriceInEth + .div(10 ** 12) + // query the the `dex` to determine the `maxPayment` you are willing to pay + .add(remainder.gt(0) ? 1 : 0); + + // query the the `dex` to determine the `maxPayment` + const { + Ok: [maxPayment], + } = (await provider.send("dex_getAmountsIn", [ + gasPriceInXRP.toNumber(), + [feeAssetId, XRP_ASSET_ID], + ])) as unknown as AmountsIn; + + return { maxPayment: BigNumber.from((maxPayment * (1 + slippage)).toString()), maxFeePerGas }; +} diff --git a/packages/utils/src/getLogger.ts b/packages/utils/src/getLogger.ts new file mode 100644 index 0000000..870ea0f --- /dev/null +++ b/packages/utils/src/getLogger.ts @@ -0,0 +1,11 @@ +import pino from "pino"; + +export type Logger = ReturnType; + +export function getLogger() { + return pino({ + transport: { + target: "pino-pretty", + }, + }); +} diff --git a/packages/utils/src/withEthersProvider.ts b/packages/utils/src/withEthersProvider.ts new file mode 100644 index 0000000..6c35881 --- /dev/null +++ b/packages/utils/src/withEthersProvider.ts @@ -0,0 +1,34 @@ +import type { NetworkName } from "@therootnetwork/api"; +import { getPublicProviderUrl } from "@therootnetwork/evm"; +import { cleanEnv, str } from "envalid"; +import { providers, Wallet } from "ethers"; +import PrettyError from "pretty-error"; + +import { getLogger, Logger } from "./getLogger"; + +const env = cleanEnv(process.env, { + CALLER_PRIVATE_KEY: str(), // private key of extrinsic caller +}); + +const pe = new PrettyError(); + +export type EthersProvider = providers.JsonRpcProvider; + +export async function withEthersProvider( + network: NetworkName, + callback: (provider: EthersProvider, wallet: Wallet, logger: Logger) => Promise +) { + const logger = getLogger(); + + const provider = new providers.JsonRpcProvider(getPublicProviderUrl(network)); + logger.info(`create a JsonRpcProvider instance with network="${network}"`); + + const wallet = new Wallet(env.CALLER_PRIVATE_KEY, provider); + logger.info(`create a Wallet from a private key of address="${wallet.address}"`); + + await callback(provider, wallet, logger).catch((error) => { + console.log(pe.render(error)); + }); + + logger.info("call ended 🎉 "); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53f4dce..2861e02 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,6 @@ importers: ethers: specifier: ^5.7.2 version: 5.7.2 - pretty-error: - specifier: ^4.0.0 - version: 4.0.0 yargs: specifier: ^17.7.2 version: 17.7.2 @@ -99,7 +96,7 @@ importers: version: 1.0.8(hardhat@2.16.0) '@nomicfoundation/hardhat-toolbox': specifier: ^3.0.0 - version: 3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.1)(@nomicfoundation/hardhat-ethers@3.0.2)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomicfoundation/hardhat-verify@1.0.3)(@typechain/ethers-v6@0.4.2)(@typechain/hardhat@8.0.0)(@types/chai@4.3.5)(@types/mocha@10.0.1)(@types/node@20.4.2)(chai@4.3.7)(ethers@6.6.1)(hardhat-gas-reporter@1.0.9)(hardhat@2.16.0)(solidity-coverage@0.8.3)(ts-node@10.9.1)(typechain@8.3.0)(typescript@5.1.6) + version: 3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.1)(@nomicfoundation/hardhat-ethers@3.0.2)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomicfoundation/hardhat-verify@1.0.3)(@typechain/ethers-v6@0.4.3)(@typechain/hardhat@8.0.0)(@types/chai@4.3.6)(@types/mocha@10.0.1)(@types/node@20.6.2)(chai@4.3.7)(ethers@6.6.1)(hardhat-gas-reporter@1.0.9)(hardhat@2.16.0)(solidity-coverage@0.8.3)(ts-node@10.9.1)(typechain@8.3.1)(typescript@5.2.2) '@nomicfoundation/hardhat-verify': specifier: ^1.0.3 version: 1.0.3(hardhat@2.16.0) @@ -108,7 +105,7 @@ importers: version: 1.0.2(@polkadot/api@10.9.1)(@polkadot/types@10.9.1) '@typechain/hardhat': specifier: ^8.0.0 - version: 8.0.0(@typechain/ethers-v6@0.4.2)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.0) + version: 8.0.0(@typechain/ethers-v6@0.4.3)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.1) chai: specifier: ^4.3.7 version: 4.3.7 @@ -120,7 +117,7 @@ importers: version: 6.6.1 hardhat: specifier: ^2.16.0 - version: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + version: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) hardhat-deploy: specifier: ^0.11.34 version: 0.11.34 @@ -289,8 +286,17 @@ importers: specifier: ^1.0.2 version: 1.0.2(@polkadot/api@10.9.1)(@polkadot/types@10.9.1) '@therootnetwork/evm': - specifier: ^1.0.0 - version: 1.0.0 + specifier: ^1.0.3 + version: 1.0.3 + pino: + specifier: ^8.15.1 + version: 8.15.1 + pino-pretty: + specifier: ^10.2.0 + version: 10.2.0 + pretty-error: + specifier: ^4.0.0 + version: 4.0.0 realm-web: specifier: ^2.0.0 version: 2.0.0 @@ -1227,7 +1233,7 @@ packages: chai-as-promised: 7.1.1(chai@4.3.7) deep-eql: 4.1.3 ethers: 6.6.1 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) ordinal: 1.0.3 dev: true @@ -1239,7 +1245,7 @@ packages: dependencies: debug: 4.3.4(supports-color@8.1.1) ethers: 6.6.1 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) transitivePeerDependencies: - supports-color dev: true @@ -1250,10 +1256,10 @@ packages: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) dev: true - /@nomicfoundation/hardhat-toolbox@3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.1)(@nomicfoundation/hardhat-ethers@3.0.2)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomicfoundation/hardhat-verify@1.0.3)(@typechain/ethers-v6@0.4.2)(@typechain/hardhat@8.0.0)(@types/chai@4.3.5)(@types/mocha@10.0.1)(@types/node@20.4.2)(chai@4.3.7)(ethers@6.6.1)(hardhat-gas-reporter@1.0.9)(hardhat@2.16.0)(solidity-coverage@0.8.3)(ts-node@10.9.1)(typechain@8.3.0)(typescript@5.1.6): + /@nomicfoundation/hardhat-toolbox@3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.1)(@nomicfoundation/hardhat-ethers@3.0.2)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomicfoundation/hardhat-verify@1.0.3)(@typechain/ethers-v6@0.4.3)(@typechain/hardhat@8.0.0)(@types/chai@4.3.6)(@types/mocha@10.0.1)(@types/node@20.6.2)(chai@4.3.7)(ethers@6.6.1)(hardhat-gas-reporter@1.0.9)(hardhat@2.16.0)(solidity-coverage@0.8.3)(ts-node@10.9.1)(typechain@8.3.1)(typescript@5.2.2): resolution: {integrity: sha512-MsteDXd0UagMksqm9KvcFG6gNKYNa3GGNCy73iQ6bEasEgg2v8Qjl6XA5hjs8o5UD5A3153B6W2BIVJ8SxYUtA==} peerDependencies: '@nomicfoundation/hardhat-chai-matchers': ^2.0.0 @@ -1278,19 +1284,19 @@ packages: '@nomicfoundation/hardhat-ethers': 3.0.2(ethers@6.6.1)(hardhat@2.16.0) '@nomicfoundation/hardhat-network-helpers': 1.0.8(hardhat@2.16.0) '@nomicfoundation/hardhat-verify': 1.0.3(hardhat@2.16.0) - '@typechain/ethers-v6': 0.4.2(ethers@6.6.1)(typechain@8.3.0)(typescript@5.1.6) - '@typechain/hardhat': 8.0.0(@typechain/ethers-v6@0.4.2)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.0) - '@types/chai': 4.3.5 + '@typechain/ethers-v6': 0.4.3(ethers@6.6.1)(typechain@8.3.1)(typescript@5.2.2) + '@typechain/hardhat': 8.0.0(@typechain/ethers-v6@0.4.3)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.1) + '@types/chai': 4.3.6 '@types/mocha': 10.0.1 - '@types/node': 20.4.2 + '@types/node': 20.6.2 chai: 4.3.7 ethers: 6.6.1 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) hardhat-gas-reporter: 1.0.9(hardhat@2.16.0) solidity-coverage: 0.8.3(hardhat@2.16.0) - ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.1.6) - typechain: 8.3.0(typescript@5.1.6) - typescript: 5.1.6 + ts-node: 10.9.1(@types/node@20.6.2)(typescript@5.2.2) + typechain: 8.3.1(typescript@5.2.2) + typescript: 5.2.2 dev: true /@nomicfoundation/hardhat-verify@1.0.3(hardhat@2.16.0): @@ -1303,7 +1309,7 @@ packages: cbor: 8.1.0 chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) lodash.clonedeep: 4.5.0 semver: 6.3.1 table: 6.8.1 @@ -1744,7 +1750,7 @@ packages: engines: {node: '>=16'} dependencies: '@polkadot/x-global': 12.3.2 - node-fetch: 3.3.1 + node-fetch: 3.3.2 tslib: 2.6.0 /@polkadot/x-global@12.3.2: @@ -1945,8 +1951,8 @@ packages: '@polkadot/api': 10.9.1 '@polkadot/types': 10.9.1 - /@therootnetwork/evm@1.0.0: - resolution: {integrity: sha512-59hu6gRIfMTpXWsiAfgj/hEGlWMkC+wkV15pVgkllOWZMuu5EfzHWylauDCmu4oMU0TeK7VaLpjZ+k15nb929g==} + /@therootnetwork/evm@1.0.3: + resolution: {integrity: sha512-Vnsu+pTTXu2d7CzR38nIHXRrOLd22hrJftBgh4L98qLurv3nHKhPzt7W08KRi6YsA1tfqIcveyUT2+vuXbHLLg==} dev: false /@trivago/prettier-plugin-sort-imports@4.1.1(prettier@2.8.8): @@ -1981,21 +1987,21 @@ packages: /@tsconfig/node16@1.0.4: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - /@typechain/ethers-v6@0.4.2(ethers@6.6.1)(typechain@8.3.0)(typescript@5.1.6): - resolution: {integrity: sha512-LPC4BBknGkWGR1TLM0d19zZ9/iXIyp2tf6+TDYMYCSbxoaP0F3jNvKVMboU1gDfr2MHaPB+fE/7ExLQ5t9RDwg==} + /@typechain/ethers-v6@0.4.3(ethers@6.6.1)(typechain@8.3.1)(typescript@5.2.2): + resolution: {integrity: sha512-TrxBsyb4ryhaY9keP6RzhFCviWYApcLCIRMPyWaKp2cZZrfaM3QBoxXTnw/eO4+DAY3l+8O0brNW0WgeQeOiDA==} peerDependencies: ethers: 6.x - typechain: ^8.3.0 + typechain: ^8.3.1 typescript: '>=4.7.0' dependencies: ethers: 6.6.1 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.1.6) - typechain: 8.3.0(typescript@5.1.6) - typescript: 5.1.6 + ts-essentials: 7.0.3(typescript@5.2.2) + typechain: 8.3.1(typescript@5.2.2) + typescript: 5.2.2 dev: true - /@typechain/hardhat@8.0.0(@typechain/ethers-v6@0.4.2)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.0): + /@typechain/hardhat@8.0.0(@typechain/ethers-v6@0.4.3)(ethers@6.6.1)(hardhat@2.16.0)(typechain@8.3.1): resolution: {integrity: sha512-XUVbqlMx8tJTOmzZCD/r196CidtNWAnTBZRcYxjLTKgcJMvc/kHQpWBnVMMB5QHxVKpYpCiz8g07FYCpG8rrjA==} peerDependencies: '@typechain/ethers-v6': ^0.4.0 @@ -2003,11 +2009,11 @@ packages: hardhat: ^2.9.9 typechain: ^8.2.0 dependencies: - '@typechain/ethers-v6': 0.4.2(ethers@6.6.1)(typechain@8.3.0)(typescript@5.1.6) + '@typechain/ethers-v6': 0.4.3(ethers@6.6.1)(typechain@8.3.1)(typescript@5.2.2) ethers: 6.6.1 fs-extra: 9.1.0 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) - typechain: 8.3.0(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) + typechain: 8.3.1(typescript@5.2.2) dev: true /@types/bn.js@4.11.6: @@ -2031,6 +2037,10 @@ packages: resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true + /@types/chai@4.3.6: + resolution: {integrity: sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==} + dev: true + /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: @@ -2088,6 +2098,10 @@ packages: /@types/node@20.4.2: resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==} + /@types/node@20.6.2: + resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==} + dev: true + /@types/node@8.10.66: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} dev: true @@ -2658,6 +2672,11 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + /autoprefixer@10.4.14(postcss@8.4.25): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} @@ -2802,7 +2821,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -2888,7 +2906,6 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true /bundle-name@3.0.0: resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} @@ -3029,7 +3046,7 @@ packages: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 /ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -3126,6 +3143,10 @@ packages: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} dev: false + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: false + /colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -3295,6 +3316,10 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} + /dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dev: false + /death@1.1.0: resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} dev: true @@ -4196,6 +4221,11 @@ packages: /eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + /evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} dependencies: @@ -4249,6 +4279,10 @@ packages: engines: {'0': node >=0.6.0} dev: true + /fast-copy@3.0.1: + resolution: {integrity: sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==} + dev: false + /fast-deep-equal@2.0.1: resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} dev: false @@ -4272,6 +4306,11 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + /fast-redact@3.3.0: + resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} + engines: {node: '>=6'} + dev: false + /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: false @@ -4488,8 +4527,8 @@ packages: dev: true optional: true - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true @@ -4599,7 +4638,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.0.4 + minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 dev: true @@ -4645,6 +4684,17 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.0.1 + once: 1.4.0 + dev: false + /global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -4797,13 +4847,13 @@ packages: dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.25 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' dev: true - /hardhat@2.16.0(ts-node@10.9.1)(typescript@5.1.6): + /hardhat@2.16.0(ts-node@10.9.1)(typescript@5.2.2): resolution: {integrity: sha512-7VQEJPQRAZdtrYUZaU9GgCpP3MBNy/pTdscARNJQMWKj5C+R7V32G5uIZKIqZ4QiqXa6CBfxxe+G+ahxUbHZHA==} engines: {node: '>=14.0.0'} hasBin: true @@ -4861,9 +4911,9 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.1.6) + ts-node: 10.9.1(@types/node@20.6.2)(typescript@5.2.2) tsort: 0.0.1 - typescript: 5.1.6 + typescript: 5.2.2 undici: 5.22.1 uuid: 8.3.2 ws: 7.5.9 @@ -4946,6 +4996,13 @@ packages: resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} dev: true + /help-me@4.2.0: + resolution: {integrity: sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==} + dependencies: + glob: 8.1.0 + readable-stream: 3.6.2 + dev: false + /hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} dependencies: @@ -5306,6 +5363,11 @@ packages: resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==} hasBin: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: false + /js-base64@3.7.5: resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} dev: false @@ -5708,7 +5770,6 @@ packages: engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -5973,8 +6034,8 @@ packages: semver: 5.7.2 dev: true - /node-fetch@2.6.12: - resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} requiresBuild: true peerDependencies: @@ -5987,8 +6048,8 @@ packages: dev: false optional: true - /node-fetch@3.3.1: - resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} + /node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: data-uri-to-buffer: 4.0.1 @@ -6146,6 +6207,10 @@ packages: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} dev: true + /on-exit-leak-free@2.1.0: + resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==} + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -6343,6 +6408,54 @@ packages: engines: {node: '>=6'} dev: true + /pino-abstract-transport@1.1.0: + resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + dependencies: + readable-stream: 4.4.2 + split2: 4.2.0 + dev: false + + /pino-pretty@10.2.0: + resolution: {integrity: sha512-tRvpyEmGtc2D+Lr3FulIZ+R1baggQ4S3xD2Ar93KixFEDx6SEAUP3W5aYuEw1C73d6ROrNcB2IXLteW8itlwhA==} + hasBin: true + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.1 + fast-safe-stringify: 2.1.1 + help-me: 4.2.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.0 + pino-abstract-transport: 1.1.0 + pump: 3.0.0 + readable-stream: 4.4.2 + secure-json-parse: 2.7.0 + sonic-boom: 3.3.0 + strip-json-comments: 3.1.1 + dev: false + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: false + + /pino@8.15.1: + resolution: {integrity: sha512-Cp4QzUQrvWCRJaQ8Lzv0mJzXVk4z2jlq8JNKMGaixC2Pz5L4l2p95TkuRvYbrEbe85NQsDKrAd4zalf7Ml6WiA==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.3.0 + on-exit-leak-free: 2.1.0 + pino-abstract-transport: 1.1.0 + pino-std-serializers: 6.2.2 + process-warning: 2.2.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.3.0 + thread-stream: 2.4.0 + dev: false + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -6453,6 +6566,15 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /process-warning@2.2.0: + resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==} + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + /promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} dependencies: @@ -6501,6 +6623,10 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -6561,7 +6687,17 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: true + + /readable-stream@4.4.2: + resolution: {integrity: sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: false /readdirp@3.2.0: resolution: {integrity: sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==} @@ -6576,6 +6712,11 @@ packages: dependencies: picomatch: 2.3.1 + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + /realm-web@2.0.0: resolution: {integrity: sha512-ANutYEvA2UsTlzPA+P8SAgQ5iK7w+9vyZUEH43ENZD1eLIzTt1T6TLptWeq0eaX9OplmRK7jiS5a+OR4NStPRg==} dependencies: @@ -6585,7 +6726,7 @@ packages: js-base64: 3.7.5 optionalDependencies: abort-controller: 3.0.0 - node-fetch: 2.6.12 + node-fetch: 2.7.0 transitivePeerDependencies: - encoding dev: false @@ -6756,7 +6897,7 @@ packages: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: - glob: 7.2.0 + glob: 7.2.3 dev: true /rimraf@3.0.2: @@ -6851,7 +6992,6 @@ packages: /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -6860,6 +7000,11 @@ packages: get-intrinsic: 1.2.1 is-regex: 1.1.4 + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: false + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true @@ -6907,6 +7052,10 @@ packages: node-gyp-build: 4.6.0 dev: true + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -7054,7 +7203,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.16.0(ts-node@10.9.1)(typescript@5.2.2) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 7.1.2 @@ -7069,6 +7218,12 @@ packages: - supports-color dev: true + /sonic-boom@3.3.0: + resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -7099,6 +7254,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -7213,7 +7373,6 @@ packages: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 - dev: true /strip-ansi@4.0.0: resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} @@ -7443,6 +7602,12 @@ packages: dependencies: any-promise: 1.3.0 + /thread-stream@2.4.0: + resolution: {integrity: sha512-xZYtOtmnA63zj04Q+F9bdEay5r47bvpo1CaNqsKi7TpoJHcotUez8Fkfo2RJWpW91lnnaApdpRbVwCWsy+ifcw==} + dependencies: + real-require: 0.2.0 + dev: false + /tiny-secp256k1@1.1.6: resolution: {integrity: sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==} engines: {node: '>=6.0.0'} @@ -7507,12 +7672,12 @@ packages: string-format: 2.0.0 dev: true - /ts-essentials@7.0.3(typescript@5.1.6): + /ts-essentials@7.0.3(typescript@5.2.2): resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 5.1.6 + typescript: 5.2.2 dev: true /ts-interface-checker@0.1.13: @@ -7548,7 +7713,7 @@ packages: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - /ts-node@10.9.1(@types/node@20.4.2)(typescript@5.1.6): + /ts-node@10.9.1(@types/node@20.6.2)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -7567,14 +7732,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.4.2 + '@types/node': 20.6.2 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.1.6 + typescript: 5.2.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -7674,8 +7839,8 @@ packages: engines: {node: '>=8'} dev: true - /typechain@8.3.0(typescript@5.1.6): - resolution: {integrity: sha512-AxtAYyOA7f2p28/JkcqrF+gnzam94VNTIbXcaUKodkrKzMX6P/XqBaP6d/OPuBZOi0WgOOmkg1zOSojX8uGkOg==} + /typechain@8.3.1(typescript@5.2.2): + resolution: {integrity: sha512-fA7clol2IP/56yq6vkMTR+4URF1nGjV82Wx6Rf09EsqD4tkzMAvEaqYxVFCavJm/1xaRga/oD55K+4FtuXwQOQ==} hasBin: true peerDependencies: typescript: '>=4.3.0' @@ -7689,8 +7854,8 @@ packages: mkdirp: 1.0.4 prettier: 2.8.8 ts-command-line-args: 2.5.1 - ts-essentials: 7.0.3(typescript@5.1.6) - typescript: 5.1.6 + ts-essentials: 7.0.3(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -7742,8 +7907,8 @@ packages: engines: {node: '>=12.20'} hasBin: true - /typescript@5.1.6: - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true dev: true From ccdf14b1e15ebb6a10862b2b5a319d5c4b35a7ec Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Wed, 20 Sep 2023 14:12:26 +1200 Subject: [PATCH 4/9] Add more details to the end output --- examples/evm/use-feeProxy/src/callERC20Transfer.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/evm/use-feeProxy/src/callERC20Transfer.ts b/examples/evm/use-feeProxy/src/callERC20Transfer.ts index eee5924..5e48b45 100644 --- a/examples/evm/use-feeProxy/src/callERC20Transfer.ts +++ b/examples/evm/use-feeProxy/src/callERC20Transfer.ts @@ -61,7 +61,14 @@ withEthersProvider("porcini", async (provider, wallet, logger) => { const [transferEvent] = filterTransactionEvents(ERC20_ABI, receipt.logs, ["Transfer"]); logger.info( - { transferEvent: { name: transferEvent.name, args: transferEvent.args } }, + { + transferEvent: { + name: transferEvent.name, + args: transferEvent.args, + transactionHash: receipt.transactionHash, + blockNumber: receipt.blockNumber, + }, + }, "receive event" ); }); From 37a77aa78016be275119687c9f18334fb665ee49 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Wed, 20 Sep 2023 17:33:50 +1200 Subject: [PATCH 5/9] Update the `substrate/use-feeProxy` with similar logging output as the `evm` one --- .../evm/use-feeProxy/src/callERC20Transfer.ts | 10 ++-- .../use-feeProxy/src/callBatchAll.ts | 40 +++++++++----- .../use-feeProxy/src/callProxyExtrinsic.ts | 52 ++++++++++++------- .../use-feeProxy/src/callSystemRemark.ts | 35 +++++++++---- packages/utils/src/sendExtrinsic.ts | 4 +- packages/utils/src/withChainApi.ts | 12 ++++- packages/utils/src/withEthersProvider.ts | 4 +- 7 files changed, 106 insertions(+), 51 deletions(-) diff --git a/examples/evm/use-feeProxy/src/callERC20Transfer.ts b/examples/evm/use-feeProxy/src/callERC20Transfer.ts index 5e48b45..1f5654f 100644 --- a/examples/evm/use-feeProxy/src/callERC20Transfer.ts +++ b/examples/evm/use-feeProxy/src/callERC20Transfer.ts @@ -62,13 +62,15 @@ withEthersProvider("porcini", async (provider, wallet, logger) => { logger.info( { - transferEvent: { - name: transferEvent.name, - args: transferEvent.args, + result: { transactionHash: receipt.transactionHash, blockNumber: receipt.blockNumber, + transferEvent: { + name: transferEvent.name, + args: transferEvent.args, + }, }, }, - "receive event" + "receive result" ); }); diff --git a/examples/substrate/use-feeProxy/src/callBatchAll.ts b/examples/substrate/use-feeProxy/src/callBatchAll.ts index 19e8cf4..65b877f 100644 --- a/examples/substrate/use-feeProxy/src/callBatchAll.ts +++ b/examples/substrate/use-feeProxy/src/callBatchAll.ts @@ -15,7 +15,7 @@ interface AmountsIn { * * Assumes the caller has some ASTO balance. */ -withChainApi("porcini", async (api, caller) => { +withChainApi("porcini", async (api, caller, logger) => { const oneASTO = 1 * Math.pow(10, 18); // 1 ASTO in `wei` unit const transferToAliceCall = api.tx.assets.transfer(ASTO_ASSET_ID, ALICE, oneASTO.toString()); const transferToBobCall = api.tx.assets.transfer(ASTO_ASSET_ID, BOB, oneASTO.toString()); @@ -27,7 +27,14 @@ withChainApi("porcini", async (api, caller) => { transferToCharlieCall, ]); - const paymentInfo = await batchAllCall.paymentInfo(caller.address); + // we need a dummy feeProxy call (with maxPayment=0) to do a proper fee estimation + const feeProxyCallForEstimation = api.tx.feeProxy.callWithFeePreferences( + ASTO_ASSET_ID, + 0, + batchAllCall + ); + + const paymentInfo = await feeProxyCallForEstimation.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); // query the the `dex` to determine the `maxPayment` you are willing to pay @@ -37,16 +44,17 @@ withChainApi("porcini", async (api, caller) => { ASTO_ASSET_ID, XRP_ASSET_ID, ])) as unknown as AmountsIn; - // allow a buffer to prevent extrinsic failure - const maxPayment = Number(amountIn * 1.5).toFixed(); + // allow a buffer to avoid slippage, 5% + const maxPayment = Number(amountIn * 1.05).toFixed(); const feeProxyCall = api.tx.feeProxy.callWithFeePreferences( ASTO_ASSET_ID, maxPayment, batchAllCall ); - const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: console }); + logger.info(`dispatch a feeProxy call with maxPayment="${maxPayment}"`); + const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: logger }); const [proxyEvent, batchEvent, aliceTransferEvent, bobTransferEvent, charlieTransferEvent] = filterExtrinsicEvents(result.events, [ "FeeProxy.CallWithFeePreferences", @@ -56,12 +64,18 @@ withChainApi("porcini", async (api, caller) => { { name: "Assets.Transferred", key: "to", data: { value: CHARLIE, type: "T::AccountId" } }, ]); - console.log("Extrinsic ID:", extrinsicId); - console.log("Extrinsic Result:", { - proxy: formatEventData(proxyEvent.event), - batchEvent: formatEventData(batchEvent.event), - aliceTransferEvent: formatEventData(aliceTransferEvent.event), - bobTransferEvent: formatEventData(bobTransferEvent.event), - charlieTransferEvent: formatEventData(charlieTransferEvent.event), - }); + logger.info( + { + result: { + extrinsicId, + blockNumber: result.blockNumber, + proxyEvent: formatEventData(proxyEvent.event), + batchEvent: formatEventData(batchEvent.event), + aliceTransferEvent: formatEventData(aliceTransferEvent.event), + bobTransferEvent: formatEventData(bobTransferEvent.event), + charlieTransferEvent: formatEventData(charlieTransferEvent.event), + }, + }, + "receive result" + ); }); diff --git a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts index 5945383..10030b7 100644 --- a/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts +++ b/examples/substrate/use-feeProxy/src/callProxyExtrinsic.ts @@ -13,25 +13,37 @@ interface AmountsIn { * Use `feeProxy.callWithFeePreferences` to trigger `system.remarkWithEvent` call via * `futurepass.proxyExtrinsic`, and have Futurepass account pays gas in ASTO. * - * Assumes the caller has a valid Futurepass account and some ASTO balance in it. + * Assumes the caller has a valid Futurepass account and some ASTO balance in that account. */ -withChainApi("porcini", async (api, caller) => { - // can be any extrinsic, using `system.remarkWithEvent` for simplicity - const remarkCall = api.tx.system.remarkWithEvent("Hello World"); +withChainApi("porcini", async (api, caller, logger) => { const fpAccount = (await api.query.futurepass.holders(caller.address)).unwrap(); - - console.log("Futurepass Details: ", { - holder: caller.address, - futurepass: fpAccount.toString(), - }); + logger.info( + { + futurepass: { + holder: caller.address, + account: fpAccount.toString(), + }, + }, + "futurepass details" + ); assert(fpAccount); + // can be any extrinsic, using `system.remarkWithEvent` for simplicity + const remarkCall = api.tx.system.remarkWithEvent("Hello World"); // wrap `remarkCall` with `proxyCall`, effetively request Futurepass account to pay for gas const futurepassCall = api.tx.futurepass.proxyExtrinsic(fpAccount, remarkCall); - const paymentInfo = await remarkCall.paymentInfo(caller.address); + // we need a dummy feeProxy call (with maxPayment=0) to do a proper fee estimation + const feeProxyCallForEstimation = api.tx.feeProxy.callWithFeePreferences( + ASTO_ASSET_ID, + 0, + futurepassCall + ); + const paymentInfo = await feeProxyCallForEstimation.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); + console.log(estimatedFee); + // query the the `dex` to determine the `maxPayment` you are willing to pay const { Ok: [amountIn], @@ -39,26 +51,30 @@ withChainApi("porcini", async (api, caller) => { ASTO_ASSET_ID, XRP_ASSET_ID, ])) as unknown as AmountsIn; - // allow a buffer to prevent extrinsic failure - const maxPayment = Number(amountIn * 1.5).toFixed(); + // allow a buffer to avoid slippage, 5% + const maxPayment = Number(amountIn * 1.05).toFixed(); const feeProxyCall = api.tx.feeProxy.callWithFeePreferences( ASTO_ASSET_ID, maxPayment, futurepassCall ); - const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: console }); + logger.info(`dispatch a feeProxy call with maxPayment="${maxPayment}"`); + const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: logger }); const [proxyEvent, futurepassEvent, remarkEvent] = filterExtrinsicEvents(result.events, [ "FeeProxy.CallWithFeePreferences", "Futurepass.ProxyExecuted", "System.Remarked", ]); - console.log("Extrinsic ID:", extrinsicId); - console.log("Extrinsic Result:", { - proxy: formatEventData(proxyEvent.event), - futurepass: formatEventData(futurepassEvent.event), - remark: formatEventData(remarkEvent.event), + logger.info({ + result: { + extrinsicId, + blockNumber: result.blockNumber, + proxyEvent: formatEventData(proxyEvent.event), + futurepassEvent: formatEventData(futurepassEvent.event), + remarkEvent: formatEventData(remarkEvent.event), + }, }); }); diff --git a/examples/substrate/use-feeProxy/src/callSystemRemark.ts b/examples/substrate/use-feeProxy/src/callSystemRemark.ts index b0513a5..bd6803b 100644 --- a/examples/substrate/use-feeProxy/src/callSystemRemark.ts +++ b/examples/substrate/use-feeProxy/src/callSystemRemark.ts @@ -14,12 +14,20 @@ interface AmountsIn { * * Assumes the caller has some ASTO balance. */ -withChainApi("porcini", async (api, caller) => { +withChainApi("porcini", async (api, caller, logger) => { // can be any extrinsic, using `system.remarkWithEvent` for simplicity const remarkCall = api.tx.system.remarkWithEvent("Hello World"); - const paymentInfo = await remarkCall.paymentInfo(caller.address); + // we need a dummy feeProxy call (with maxPayment=0) to do a proper fee estimation + const feeProxyCallForEstimation = api.tx.feeProxy.callWithFeePreferences( + ASTO_ASSET_ID, + 0, + remarkCall + ); + const paymentInfo = await feeProxyCallForEstimation.paymentInfo(caller.address); const estimatedFee = paymentInfo.partialFee.toString(); + logger.info(`prepare a "system.remark" call with estimatedFee="${estimatedFee}"`); + // query the the `dex` to determine the `maxPayment` you are willing to pay const { Ok: [amountIn], @@ -27,24 +35,31 @@ withChainApi("porcini", async (api, caller) => { ASTO_ASSET_ID, XRP_ASSET_ID, ])) as unknown as AmountsIn; - // allow a buffer to prevent extrinsic failure - const maxPayment = Number(amountIn * 1.5).toFixed(); + // allow a buffer to avoid slippage, 5% + const maxPayment = Number(amountIn * 1.05).toFixed(); const feeProxyCall = api.tx.feeProxy.callWithFeePreferences( ASTO_ASSET_ID, maxPayment, remarkCall ); - const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: console }); + logger.info(`dispatch a feeProxy call with maxPayment="${maxPayment}"`); + const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: logger }); const [proxyEvent, remarkEvent] = filterExtrinsicEvents(result.events, [ "FeeProxy.CallWithFeePreferences", "System.Remarked", ]); - console.log("Extrinsic ID:", extrinsicId); - console.log("Extrinsic Result:", { - proxy: formatEventData(proxyEvent.event), - remark: formatEventData(remarkEvent.event), - }); + logger.info( + { + result: { + extrinsicId, + blockNumber: result.blockNumber, + proxyEvent: formatEventData(proxyEvent.event), + remarkEvent: formatEventData(remarkEvent.event), + }, + }, + "receive result" + ); }); diff --git a/packages/utils/src/sendExtrinsic.ts b/packages/utils/src/sendExtrinsic.ts index a57a7f3..968ab53 100644 --- a/packages/utils/src/sendExtrinsic.ts +++ b/packages/utils/src/sendExtrinsic.ts @@ -15,7 +15,7 @@ export interface SubmittableResponse { } type SubmitOptions = Partial & { - log?: typeof console; + log?: { info: (msg: string) => void }; }; /** @@ -39,7 +39,7 @@ export async function sendExtrinsic( .signAndSend(signer, signerOptions, (result) => { const { status, dispatchError, txHash, txIndex, blockNumber } = result as SubmittableResultValue; - log?.debug(`Extrinsic Status: `, status.type); + log?.info(`extrinsic status="${status.type}"`); if (!status.isFinalized) return; if (!txIndex || !blockNumber) return; diff --git a/packages/utils/src/withChainApi.ts b/packages/utils/src/withChainApi.ts index e27870a..0256ab0 100644 --- a/packages/utils/src/withChainApi.ts +++ b/packages/utils/src/withChainApi.ts @@ -5,6 +5,7 @@ import PrettyError from "pretty-error"; import { createKeyring, type Signer } from "./createKeyring"; import { getChainApi } from "./getChainApi"; +import { getLogger, type Logger } from "./getLogger"; const env = cleanEnv(process.env, { CALLER_PRIVATE_KEY: str(), // private key of extrinsic caller @@ -14,14 +15,21 @@ const pe = new PrettyError(); export async function withChainApi( network: NetworkName | "local", - callback: (api: ApiPromise, signer: Signer) => Promise + callback: (api: ApiPromise, signer: Signer, logger: Logger) => Promise ) { + const logger = getLogger(); + const [api, signer] = await Promise.all([ getChainApi(network), createKeyring(env.CALLER_PRIVATE_KEY), ]); - await callback(api, signer).catch((error) => console.log(pe.render(error))); + logger.info(`create an ApiPromise instance with network="${network}"`); + logger.info(`create a Signer instance from a private key of address="${signer.address}"`); + + await callback(api, signer, logger).catch((error) => console.log(pe.render(error))); await api.disconnect(); + + logger.info("call ended 🎉 "); } diff --git a/packages/utils/src/withEthersProvider.ts b/packages/utils/src/withEthersProvider.ts index 6c35881..795c5dc 100644 --- a/packages/utils/src/withEthersProvider.ts +++ b/packages/utils/src/withEthersProvider.ts @@ -4,7 +4,7 @@ import { cleanEnv, str } from "envalid"; import { providers, Wallet } from "ethers"; import PrettyError from "pretty-error"; -import { getLogger, Logger } from "./getLogger"; +import { getLogger, type Logger } from "./getLogger"; const env = cleanEnv(process.env, { CALLER_PRIVATE_KEY: str(), // private key of extrinsic caller @@ -24,7 +24,7 @@ export async function withEthersProvider( logger.info(`create a JsonRpcProvider instance with network="${network}"`); const wallet = new Wallet(env.CALLER_PRIVATE_KEY, provider); - logger.info(`create a Wallet from a private key of address="${wallet.address}"`); + logger.info(`create a Wallet instance from a private key of address="${wallet.address}"`); await callback(provider, wallet, logger).catch((error) => { console.log(pe.render(error)); From 0250aa059d3e2afd93ee0e12277832dfb9cceb24 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Wed, 20 Sep 2023 22:46:47 +1200 Subject: [PATCH 6/9] Switch over to `tsx` for better performance --- examples/evm/use-feeProxy/package.json | 2 +- examples/substrate/use-feeProxy/package.json | 2 +- package.json | 1 + pnpm-lock.yaml | 271 ++++++++++++++++++- 4 files changed, 269 insertions(+), 7 deletions(-) diff --git a/examples/evm/use-feeProxy/package.json b/examples/evm/use-feeProxy/package.json index db76e38..23054e9 100644 --- a/examples/evm/use-feeProxy/package.json +++ b/examples/evm/use-feeProxy/package.json @@ -1,6 +1,6 @@ { "scripts": { - "call": "ts-node --project ../../../tsconfig.json", + "call": "tsx --tsconfig ../../../tsconfig.json", "call:callERC20Transfer": "pnpm call src/callERC20Transfer.ts" } } diff --git a/examples/substrate/use-feeProxy/package.json b/examples/substrate/use-feeProxy/package.json index 9709809..5ceb54d 100644 --- a/examples/substrate/use-feeProxy/package.json +++ b/examples/substrate/use-feeProxy/package.json @@ -1,6 +1,6 @@ { "scripts": { - "call": "ts-node --project ../../../tsconfig.json", + "call": "tsx --tsconfig ../../../tsconfig.json", "call:callSystemRemark": "pnpm call src/callSystemRemark.ts", "call:callProxyExtrinsic": "pnpm call src/callProxyExtrinsic.ts", "call:callBatchAll": "pnpm call src/callBatchAll.ts" diff --git a/package.json b/package.json index 9cf474e..c2027df 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "prettier": "^2.8.8", "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", + "tsx": "^3.12.10", "typescript": "^5.0.4", "xrpl": "^2.7.0", "yargs": "^17.7.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2861e02..ea06b9e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,6 +54,9 @@ importers: tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 + tsx: + specifier: ^3.12.10 + version: 3.12.10 typescript: specifier: ^5.0.4 version: 5.0.4 @@ -473,6 +476,225 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.9 + /@esbuild-kit/cjs-loader@2.4.4: + resolution: {integrity: sha512-NfsJX4PdzhwSkfJukczyUiZGc7zNNWZcEAyqeISpDnn0PTfzMJR1aR8xAIPskBejIxBJbIgCCMzbaYa9SXepIg==} + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.7.0 + dev: true + + /@esbuild-kit/core-utils@3.3.2: + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + dev: true + + /@esbuild-kit/esm-loader@2.6.5: + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.7.0 + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.40.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3678,6 +3900,36 @@ packages: resolution: {integrity: sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==} dev: true + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -3751,7 +4003,7 @@ packages: eslint: 8.40.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.40.0) eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.59.6)(eslint@8.40.0) - get-tsconfig: 4.6.2 + get-tsconfig: 4.7.0 globby: 13.2.2 is-core-module: 2.12.1 is-glob: 4.0.3 @@ -4586,11 +4838,10 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.2.1 - /get-tsconfig@4.6.2: - resolution: {integrity: sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==} + /get-tsconfig@4.7.0: + resolution: {integrity: sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==} dependencies: resolve-pkg-maps: 1.0.0 - dev: false /getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -6860,7 +7111,6 @@ packages: /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: false /resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} @@ -7789,6 +8039,17 @@ packages: tslib: 1.14.1 typescript: 5.0.4 + /tsx@3.12.10: + resolution: {integrity: sha512-2+46h4xvUt1aLDNvk5YBT8Uzw+b7BolGbn7iSMucYqCXZiDc+1IMghLVdw8kKjING32JFOeO+Am9posvjkeclA==} + hasBin: true + dependencies: + '@esbuild-kit/cjs-loader': 2.4.4 + '@esbuild-kit/core-utils': 3.3.2 + '@esbuild-kit/esm-loader': 2.6.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: From 12154cd1199b5883f57b0c5aaf344beac865d735 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Thu, 21 Sep 2023 12:44:18 +1200 Subject: [PATCH 7/9] Add the slippage to `maxFeePerGas` since `maxPayment` is derived from it --- packages/utils/src/getFeeProxyPricePair.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/getFeeProxyPricePair.ts b/packages/utils/src/getFeeProxyPricePair.ts index 29667c7..92a5268 100644 --- a/packages/utils/src/getFeeProxyPricePair.ts +++ b/packages/utils/src/getFeeProxyPricePair.ts @@ -19,7 +19,7 @@ export async function getFeeProxyPricePair( assert(maxFeePerGas); // convert gasPrice in ETH to gasPrice in XRP, which has different decimals, one is 18 & one is 6 - const gasPriceInEth = gasEstimate.mul(maxFeePerGas); + const gasPriceInEth = gasEstimate.mul((maxFeePerGas.toNumber() * (1 + slippage)).toFixed()); const remainder = gasPriceInEth.mod(10 ** 12); const gasPriceInXRP = gasPriceInEth .div(10 ** 12) @@ -34,5 +34,5 @@ export async function getFeeProxyPricePair( [feeAssetId, XRP_ASSET_ID], ])) as unknown as AmountsIn; - return { maxPayment: BigNumber.from((maxPayment * (1 + slippage)).toString()), maxFeePerGas }; + return { maxPayment: BigNumber.from(maxPayment.toString()), maxFeePerGas }; } From 906a5fc25fc3a016b0544f94240e8917357e40bc Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Thu, 21 Sep 2023 13:59:59 +1200 Subject: [PATCH 8/9] Move some of the deps to the top level --- .../evm/use-feeProxy/src/callERC20Transfer.ts | 2 +- package.json | 8 ++- packages/utils/package.json | 6 --- pnpm-lock.yaml | 52 +++++++++---------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/evm/use-feeProxy/src/callERC20Transfer.ts b/examples/evm/use-feeProxy/src/callERC20Transfer.ts index 1f5654f..aabe58a 100644 --- a/examples/evm/use-feeProxy/src/callERC20Transfer.ts +++ b/examples/evm/use-feeProxy/src/callERC20Transfer.ts @@ -1,7 +1,7 @@ +import { ERC20_ABI } from "@therootnetwork/evm"; import { ALICE } from "@trne/utils/accounts"; import { filterTransactionEvents } from "@trne/utils/filterTransactionEvents"; import { getERC20Contract } from "@trne/utils/getERC20Contract"; -import { ERC20_ABI } from "@trne/utils/getERC20PrecompileAddress"; import { getFeeProxyContract } from "@trne/utils/getFeeProxyContract"; import { getFeeProxyPricePair } from "@trne/utils/getFeeProxyPricePair"; import { ASTO_ASSET_ID, SYLO_ASSET_ID } from "@trne/utils/porcini-assets"; diff --git a/package.json b/package.json index c2027df..2c24ea1 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,13 @@ "dependencies": { "envalid": "^7.3.1", "ethers": "^5.7.2", - "yargs": "^17.7.2" + "yargs": "^17.7.2", + "@polkadot/api": "^10.9.1", + "@polkadot/keyring": "^12.3.2", + "@polkadot/util": "^12.3.2", + "@polkadot/util-crypto": "^12.3.2", + "@therootnetwork/api": "^1.0.2", + "@therootnetwork/evm": "^1.0.3" }, "devDependencies": { "@eslint/create-config": "^0.4.3", diff --git a/packages/utils/package.json b/packages/utils/package.json index a371980..b233b24 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,12 +1,6 @@ { "name": "@trne/utils", "dependencies": { - "@polkadot/api": "^10.9.1", - "@polkadot/keyring": "^12.3.2", - "@polkadot/util": "^12.3.2", - "@polkadot/util-crypto": "^12.3.2", - "@therootnetwork/api": "^1.0.2", - "@therootnetwork/evm": "^1.0.3", "realm-web": "^2.0.0", "pino": "^8.15.1", "pino-pretty": "^10.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea06b9e..45f1043 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,24 @@ importers: .: dependencies: + '@polkadot/api': + specifier: ^10.9.1 + version: 10.9.1 + '@polkadot/keyring': + specifier: ^12.3.2 + version: 12.3.2(@polkadot/util-crypto@12.3.2)(@polkadot/util@12.3.2) + '@polkadot/util': + specifier: ^12.3.2 + version: 12.3.2 + '@polkadot/util-crypto': + specifier: ^12.3.2 + version: 12.3.2(@polkadot/util@12.3.2) + '@therootnetwork/api': + specifier: ^1.0.2 + version: 1.0.2(@polkadot/api@10.9.1)(@polkadot/types@10.9.1) + '@therootnetwork/evm': + specifier: ^1.0.3 + version: 1.0.3 envalid: specifier: ^7.3.1 version: 7.3.1 @@ -273,24 +291,6 @@ importers: packages/utils: dependencies: - '@polkadot/api': - specifier: ^10.9.1 - version: 10.9.1 - '@polkadot/keyring': - specifier: ^12.3.2 - version: 12.3.2(@polkadot/util-crypto@12.3.2)(@polkadot/util@12.3.2) - '@polkadot/util': - specifier: ^12.3.2 - version: 12.3.2 - '@polkadot/util-crypto': - specifier: ^12.3.2 - version: 12.3.2(@polkadot/util@12.3.2) - '@therootnetwork/api': - specifier: ^1.0.2 - version: 1.0.2(@polkadot/api@10.9.1)(@polkadot/types@10.9.1) - '@therootnetwork/evm': - specifier: ^1.0.3 - version: 1.0.3 pino: specifier: ^8.15.1 version: 8.15.1 @@ -2241,13 +2241,13 @@ packages: /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 /@types/chai-as-promised@7.1.5: resolution: {integrity: sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==} @@ -2266,20 +2266,20 @@ packages: /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/form-data@0.0.33: resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/json-schema@7.0.12: @@ -2319,10 +2319,10 @@ packages: /@types/node@20.4.2: resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==} + dev: true /@types/node@20.6.2: resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==} - dev: true /@types/node@8.10.66: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -2331,7 +2331,7 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/prettier@2.7.3: @@ -2371,7 +2371,7 @@ packages: /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 20.4.2 + '@types/node': 20.6.2 dev: true /@types/semver@7.5.0: From 2911f1314d42984ae4d354e41c81a642cbd537b1 Mon Sep 17 00:00:00 2001 From: Ken Vu Date: Thu, 21 Sep 2023 14:00:17 +1200 Subject: [PATCH 9/9] Add `callEVMCall.ts` to the example --- examples/substrate/use-feeProxy/README.md | 3 + examples/substrate/use-feeProxy/package.json | 3 +- .../substrate/use-feeProxy/src/callEVMCall.ts | 95 +++++++++++++++++++ packages/utils/src/getFeeProxyPricePair.ts | 19 ++-- packages/utils/src/withEthersProvider.ts | 16 +++- 5 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 examples/substrate/use-feeProxy/src/callEVMCall.ts diff --git a/examples/substrate/use-feeProxy/README.md b/examples/substrate/use-feeProxy/README.md index af5828a..23254b2 100644 --- a/examples/substrate/use-feeProxy/README.md +++ b/examples/substrate/use-feeProxy/README.md @@ -25,4 +25,7 @@ pnpm call:callProxyExtrinsic # `feeProxy.callWithFeePreferences` that wraps around `utility.batchAll` pnpm call:callBatchAll +# `feeProxy.callWithFeePreferences` that wraps around `evm.call` +pnpm call:callEVMCall + ``` diff --git a/examples/substrate/use-feeProxy/package.json b/examples/substrate/use-feeProxy/package.json index 5ceb54d..67b03eb 100644 --- a/examples/substrate/use-feeProxy/package.json +++ b/examples/substrate/use-feeProxy/package.json @@ -3,6 +3,7 @@ "call": "tsx --tsconfig ../../../tsconfig.json", "call:callSystemRemark": "pnpm call src/callSystemRemark.ts", "call:callProxyExtrinsic": "pnpm call src/callProxyExtrinsic.ts", - "call:callBatchAll": "pnpm call src/callBatchAll.ts" + "call:callBatchAll": "pnpm call src/callBatchAll.ts", + "call:callEVMCall": "pnpm call src/callEVMCall.ts" } } diff --git a/examples/substrate/use-feeProxy/src/callEVMCall.ts b/examples/substrate/use-feeProxy/src/callEVMCall.ts new file mode 100644 index 0000000..ccfd7b0 --- /dev/null +++ b/examples/substrate/use-feeProxy/src/callEVMCall.ts @@ -0,0 +1,95 @@ +import { ERC20_ABI } from "@therootnetwork/evm"; +import { ALICE } from "@trne/utils/accounts"; +import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents"; +import { formatEventData } from "@trne/utils/formatEventData"; +import { getERC20Contract } from "@trne/utils/getERC20Contract"; +import { getFeeProxyPricePair } from "@trne/utils/getFeeProxyPricePair"; +import { ASTO_ASSET_ID, SYLO_ASSET_ID, XRP_ASSET_ID } from "@trne/utils/porcini-assets"; +import { sendExtrinsic } from "@trne/utils/sendExtrinsic"; +import { withChainApi } from "@trne/utils/withChainApi"; +import { provideEthersProvider } from "@trne/utils/withEthersProvider"; +import { BigNumber, utils } from "ethers"; + +interface AmountsIn { + Ok: [number, number]; +} + +/** + * Use `feeProxy.callWithFeePreferencs` to trigger `evm.call` call + * + * Assumes the caller has some ASTO balance. + */ +withChainApi("porcini", async (api, caller, logger) => { + // setup the evmCall + const { provider, wallet } = await provideEthersProvider("porcini"); + const transferToken = getERC20Contract(SYLO_ASSET_ID).connect(wallet); + const transferAmount = utils.parseUnits("1.0", 18); // 1 SYLO + const transferInput = new utils.Interface(ERC20_ABI).encodeFunctionData("transfer", [ + ALICE, + transferAmount, + ]); + const transferEstimate = await transferToken.estimateGas.transfer(ALICE, transferAmount); + const { maxFeePerGas, estimateGasCost } = await getFeeProxyPricePair( + provider, + transferEstimate, + ASTO_ASSET_ID, + 0.05 + ); + const evmCall = api.tx.evm.call( + caller.address, + transferToken.address, + transferInput, + 0, + transferEstimate.toString(), + maxFeePerGas.toString(), + 0, + null, + [] + ); + + // we need a dummy feeProxy call (with maxPayment=0) to do a proper fee estimation + const feeProxyCallForEstimation = api.tx.feeProxy.callWithFeePreferences( + ASTO_ASSET_ID, + 0, + evmCall + ); + const feeProxyPaymentInfo = await feeProxyCallForEstimation.paymentInfo(caller.address); + + // we need to add the actual estimate cost for the EVM layer call as part of the estimation + const estimatedFee = BigNumber.from(feeProxyPaymentInfo.partialFee.toString()) + .add(estimateGasCost) + .toString(); + + logger.info(`prepare a "evm.call" call with estimatedFee="${estimatedFee}"`); + + // query the the `dex` to determine the `maxPayment` you are willing to pay + const { + Ok: [amountIn], + } = (await api.rpc.dex.getAmountsIn(estimatedFee, [ + ASTO_ASSET_ID, + XRP_ASSET_ID, + ])) as unknown as AmountsIn; + + // allow a buffer to avoid slippage, 5% + const maxPayment = Number(amountIn * 1.05).toFixed(); + const feeProxyCall = api.tx.feeProxy.callWithFeePreferences(ASTO_ASSET_ID, maxPayment, evmCall); + logger.info(`dispatch a feeProxy call with maxPayment="${maxPayment}"`); + const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: logger }); + + const [proxyEvent, aliceTransferEvent] = filterExtrinsicEvents(result.events, [ + "FeeProxy.CallWithFeePreferences", + { name: "Assets.Transferred", key: "to", data: { value: ALICE, type: "T::AccountId" } }, + ]); + + logger.info( + { + result: { + extrinsicId, + blockNumber: result.blockNumber, + proxyEvent: formatEventData(proxyEvent.event), + aliceTransferEvent: formatEventData(aliceTransferEvent.event), + }, + }, + "receive result" + ); +}); diff --git a/packages/utils/src/getFeeProxyPricePair.ts b/packages/utils/src/getFeeProxyPricePair.ts index 92a5268..160ea4a 100644 --- a/packages/utils/src/getFeeProxyPricePair.ts +++ b/packages/utils/src/getFeeProxyPricePair.ts @@ -13,26 +13,27 @@ export async function getFeeProxyPricePair( gasEstimate: BigNumber, feeAssetId: number, slippage = 0 -): Promise<{ maxPayment: BigNumber; maxFeePerGas: BigNumber }> { +): Promise<{ maxPayment: BigNumber; maxFeePerGas: BigNumber; estimateGasCost: BigNumber }> { const { lastBaseFeePerGas: maxFeePerGas } = await provider.getFeeData(); assert(maxFeePerGas); // convert gasPrice in ETH to gasPrice in XRP, which has different decimals, one is 18 & one is 6 - const gasPriceInEth = gasEstimate.mul((maxFeePerGas.toNumber() * (1 + slippage)).toFixed()); - const remainder = gasPriceInEth.mod(10 ** 12); - const gasPriceInXRP = gasPriceInEth - .div(10 ** 12) - // query the the `dex` to determine the `maxPayment` you are willing to pay - .add(remainder.gt(0) ? 1 : 0); + const gasCostInEth = gasEstimate.mul((maxFeePerGas.toNumber() * (1 + slippage)).toFixed()); + const remainder = gasCostInEth.mod(10 ** 12); + const gasCostInXRP = gasCostInEth.div(10 ** 12).add(remainder.gt(0) ? 1 : 0); // query the the `dex` to determine the `maxPayment` const { Ok: [maxPayment], } = (await provider.send("dex_getAmountsIn", [ - gasPriceInXRP.toNumber(), + gasCostInXRP.toNumber(), [feeAssetId, XRP_ASSET_ID], ])) as unknown as AmountsIn; - return { maxPayment: BigNumber.from(maxPayment.toString()), maxFeePerGas }; + return { + estimateGasCost: gasCostInXRP, + maxPayment: BigNumber.from(maxPayment.toString()), + maxFeePerGas, + }; } diff --git a/packages/utils/src/withEthersProvider.ts b/packages/utils/src/withEthersProvider.ts index 795c5dc..1836a72 100644 --- a/packages/utils/src/withEthersProvider.ts +++ b/packages/utils/src/withEthersProvider.ts @@ -18,6 +18,16 @@ export async function withEthersProvider( network: NetworkName, callback: (provider: EthersProvider, wallet: Wallet, logger: Logger) => Promise ) { + const { provider, wallet, logger } = await provideEthersProvider(network); + + await callback(provider, wallet, logger).catch((error) => { + console.log(pe.render(error)); + }); + + logger.info("call ended 🎉 "); +} + +export async function provideEthersProvider(network: NetworkName) { const logger = getLogger(); const provider = new providers.JsonRpcProvider(getPublicProviderUrl(network)); @@ -26,9 +36,5 @@ export async function withEthersProvider( const wallet = new Wallet(env.CALLER_PRIVATE_KEY, provider); logger.info(`create a Wallet instance from a private key of address="${wallet.address}"`); - await callback(provider, wallet, logger).catch((error) => { - console.log(pe.render(error)); - }); - - logger.info("call ended 🎉 "); + return { provider, wallet, logger }; }