From e42659babf0180b315c101191807a084dadc673a Mon Sep 17 00:00:00 2001 From: ilya saldin Date: Tue, 30 Apr 2024 17:26:17 +0500 Subject: [PATCH] feat(web3.js): web3.js support --- commitlint.config.ts | 6 +- examples/nodejs-example/web3-example.ts | 122 +++ examples/sandbox/.eslintrc.json | 2 +- examples/sandbox/src/app/app.tsx | 34 +- .../src/components/contract-testing/index.tsx | 61 +- .../sandbox/src/components/signer-test.tsx | 3 +- examples/sandbox/src/components/vaults.tsx | 10 +- .../src/components/workflows-web3js.tsx | 205 +++++ examples/sandbox/src/components/workflows.tsx | 46 +- examples/sandbox/src/main.tsx | 2 + package-lock.json | 662 +++++++++++++- package.json | 5 +- packages/core/README.md | 2 +- packages/core/src/lib/contracts/types.ts | 11 +- packages/core/src/lib/ditto-sdk.ts | 8 +- .../core/src/lib/network/api-client/types.ts | 2 +- packages/core/src/lib/signer/types.ts | 9 +- packages/core/src/lib/types.ts | 7 +- .../src/lib/vaults/smart-wallet-factory.ts | 16 +- .../lib/vaults/smart-wallet/smart-wallet.ts | 9 +- packages/core/src/lib/workflow/factory.ts | 2 +- .../lib/workflow/triggers/price-trigger.ts | 7 +- packages/ethers/package-lock.json | 9 +- .../src/lib/contract/ethers-contract.ts | 12 +- .../ethers/src/lib/signer/ethers-signer.ts | 17 +- packages/web3js/.eslintignore | 1 + packages/web3js/.eslintrc.json | 30 + packages/web3js/README.md | 69 ++ packages/web3js/package-lock.json | 859 ++++++++++++++++++ packages/web3js/package.json | 13 + packages/web3js/project.json | 32 + packages/web3js/src/index.ts | 5 + .../lib/contract/web3js-contract-factory.ts | 22 + .../lib/contract/web3js-contract-interface.ts | 15 + .../src/lib/contract/web3js-contract.ts | 66 ++ .../web3js/src/lib/signer/web3js-signer.ts | 68 ++ .../web3js/src/lib/utils/deferred-promise.ts | 16 + .../src/lib/utils/get-method-from-abi.ts | 17 + .../utils/web-promi-event-to-tx-promise.ts | 30 + packages/web3js/tsconfig.json | 24 + packages/web3js/tsconfig.lib.json | 10 + packages/web3js/tsconfig.spec.json | 20 + packages/web3js/vite.config.ts | 24 + tsconfig.base.json | 3 +- 44 files changed, 2463 insertions(+), 130 deletions(-) create mode 100644 examples/nodejs-example/web3-example.ts create mode 100644 examples/sandbox/src/components/workflows-web3js.tsx create mode 100644 packages/web3js/.eslintignore create mode 100644 packages/web3js/.eslintrc.json create mode 100644 packages/web3js/README.md create mode 100644 packages/web3js/package-lock.json create mode 100644 packages/web3js/package.json create mode 100644 packages/web3js/project.json create mode 100644 packages/web3js/src/index.ts create mode 100644 packages/web3js/src/lib/contract/web3js-contract-factory.ts create mode 100644 packages/web3js/src/lib/contract/web3js-contract-interface.ts create mode 100644 packages/web3js/src/lib/contract/web3js-contract.ts create mode 100644 packages/web3js/src/lib/signer/web3js-signer.ts create mode 100644 packages/web3js/src/lib/utils/deferred-promise.ts create mode 100644 packages/web3js/src/lib/utils/get-method-from-abi.ts create mode 100644 packages/web3js/src/lib/utils/web-promi-event-to-tx-promise.ts create mode 100644 packages/web3js/tsconfig.json create mode 100644 packages/web3js/tsconfig.lib.json create mode 100644 packages/web3js/tsconfig.spec.json create mode 100644 packages/web3js/vite.config.ts diff --git a/commitlint.config.ts b/commitlint.config.ts index 53d28a2..b8a089c 100644 --- a/commitlint.config.ts +++ b/commitlint.config.ts @@ -35,7 +35,11 @@ export default { 'test', ], ] as [RuleConfigSeverity, RuleConfigCondition, string[]], - 'scope-enum': [RuleConfigSeverity.Error, 'always', ['global', 'core', 'examples', 'ethers']], + 'scope-enum': [ + RuleConfigSeverity.Error, + 'always', + ['global', 'core', 'examples', 'ethers', 'web3.js'], + ], }, prompt: { questions: { diff --git a/examples/nodejs-example/web3-example.ts b/examples/nodejs-example/web3-example.ts new file mode 100644 index 0000000..95f36f1 --- /dev/null +++ b/examples/nodejs-example/web3-example.ts @@ -0,0 +1,122 @@ +import { + Address, + Chain, + CommonBuilderOptions, + InMemoryStorage, + PriceTrigger, + Provider, + SmartWalletFactory, + TimeBasedTrigger, + TimeScale, + tokens, + UniswapSwapActionCallDataBuilder, + WorkflowsFactory, +} from '@ditto-network/core'; +import { Web3jsContractFactory, Web3jsSigner } from '@ditto-network/web3.js'; +import { Web3 } from 'web3'; + +(async () => { + const chainId = Chain.Polygon; + + const web3 = new Web3(process.env.INFURA_API_URL!); + const accounts = web3.eth.accounts.wallet.add(`0x${process.env.PRIVATE_KEY!}`); + const account = accounts[0].address! as Address; + + const txParamsBuildFn = async () => { + const { baseFeePerGas } = await web3.eth.getBlock('pending'); + + return { + from: account, + maxFeePerGas: `${BigInt(2) * baseFeePerGas!}`, + maxPriorityFeePerGas: `${baseFeePerGas! / BigInt(2)}`, + }; + }; + + const storage = new InMemoryStorage(); + const dittoProvider = new Provider({ + signer: new Web3jsSigner(web3, account, txParamsBuildFn), + storage, + contractFactory: new Web3jsContractFactory(web3, txParamsBuildFn), + }); + + const needAuth = await dittoProvider.needAuthentication(); + if (needAuth) { + await dittoProvider.authenticate(); + } + + const accountAddress = await dittoProvider.getSigner().getAddress(); + + const swFactory = new SmartWalletFactory(dittoProvider); + // const vault = await swFactory.getDefaultOrCreateVault(chainId); + const vaultAddress = '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919' as Address; // vault.getAddress()!; + + const commonConfig = { + chainId, + recipient: vaultAddress, + accountAddress, + vaultAddress, + provider: dittoProvider, + } satisfies CommonBuilderOptions; + + const workflowsFactory = new WorkflowsFactory(dittoProvider); + + const wmatic = tokens.wrappedNative[Chain.Polygon]; + const usdt = tokens.stableCoins[Chain.Polygon].USDT; + + const timeTrigger = new TimeBasedTrigger( + { + repeatTimes: 2, + startAtTimestamp: new Date().getTime() / 1000 + 120, + cycle: { + frequency: 1, + scale: TimeScale.Minutes, + }, + }, + commonConfig + ); + + // rate = how much of fromToken you should pay to get one toToken + // rate should be: + // a) higher than triggerAtPrice if priceMustBeHigherThan is true + // b) lower than triggerAtPrice if priceMustBeHigherThan is false + // in this case rate is 0.88 (0.88 USDT for 1 WMATIC) + // triggerAtPrice is 0.3 (300000 / 1e6) + // current rate is higher than triggerAtPrice and priceMustBeHigherThan is true so the trigger should be triggered + const priceTrigger = new PriceTrigger( + { + uniswapPoolFeeTier: 3000, + triggerAtPrice: '300000', + priceMustBeHigherThan: true, + fromToken: usdt, + toToken: wmatic, + }, + commonConfig + ); + + const usePriceTrigger = true; + + const wf = await workflowsFactory.create({ + name: 'My first workflow', + triggers: [usePriceTrigger ? priceTrigger : timeTrigger], + actions: [ + new UniswapSwapActionCallDataBuilder( + { + fromToken: wmatic, + toToken: usdt, + fromAmount: `333444555000000`, + slippagePercent: 0.05, + providerStrategy: { + type: 'nodejs', + chainId: chainId, + rpcUrl: process.env.INFURA_API_URL!, + }, + }, + commonConfig + ), + ], + chainId, + }); + + const hash = await wf.buildAndDeploy(commonConfig.vaultAddress, commonConfig.accountAddress); + console.log('Workflow hash:', hash); +})(); diff --git a/examples/sandbox/.eslintrc.json b/examples/sandbox/.eslintrc.json index c5bdb41..a39ac5d 100644 --- a/examples/sandbox/.eslintrc.json +++ b/examples/sandbox/.eslintrc.json @@ -1,5 +1,5 @@ { - "extends": ["plugin:@nx/react", "../.eslintrc.json"], + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], "ignorePatterns": ["!**/*"], "overrides": [ { diff --git a/examples/sandbox/src/app/app.tsx b/examples/sandbox/src/app/app.tsx index 79c9ec8..86fac74 100644 --- a/examples/sandbox/src/app/app.tsx +++ b/examples/sandbox/src/app/app.tsx @@ -3,14 +3,8 @@ import { Button, Popover, PopoverContent, PopoverTrigger } from '../components/u import { formatAddress } from '../lib/utils'; import { useSDK, MetaMaskProvider } from '@metamask/sdk-react'; import { Link } from 'react-router-dom'; -import { - BrowserStorage, - Chain, - EthersContractFactory, - EthersSigner, - Provider, - SmartWalletFactory, -} from '@ditto-network/core'; +import { BrowserStorage, Chain, Provider, SmartWalletFactory } from '@ditto-network/core'; +import { EthersContractFactory, EthersSigner } from '@ditto-network/ethers'; import { ethers } from 'ethers'; // https://github.com/Uniswap/smart-order-router/issues/484 @@ -121,16 +115,6 @@ export function App() { setAuth(authResult); }; - const handlePredictVaultAddressSDKClick = async () => { - console.log('handlePredictVaultAddressSDKClick'); - if (!provider) return; - - const smartWalletFactory = new SmartWalletFactory(provider, Chain.Polygon); - - const addr = await smartWalletFactory.predictVaultAddress(); - setSmartWalletAddress(addr as string); - }; - return (
@@ -170,20 +154,6 @@ export function App() {

Smart Wallet

Create a smart wallet and deploy it to the blockchain

- -
-
- -
-

- This will predict the address of the smart wallet based on the wallet address -

-

- Predicted address: {smartWalletAddress ? smartWalletAddress : '❌ Not predicted'} -

-

Workflow

diff --git a/examples/sandbox/src/components/contract-testing/index.tsx b/examples/sandbox/src/components/contract-testing/index.tsx index dd61e14..59a8a5a 100644 --- a/examples/sandbox/src/components/contract-testing/index.tsx +++ b/examples/sandbox/src/components/contract-testing/index.tsx @@ -1,7 +1,13 @@ import { useEffect, useState } from 'react'; -import { ethers } from 'ethers'; -import { BrowserStorage, EthersContractFactory, EthersSigner, Provider } from '@ditto-network/core'; +import { + Address, + BrowserStorage, + MutationTransactionReturnType, + Provider, +} from '@ditto-network/core'; import storageAbi from './storage.abi.json'; +import { Web3 } from 'web3'; +import { Web3jsContractFactory, Web3jsSigner } from '@ditto-network/web3.js'; export const ContractTesting = () => { const [auth, setAuth] = useState(false); @@ -9,19 +15,47 @@ export const ContractTesting = () => { const [hash, setHash] = useState(''); const [value, setValue] = useState(''); - useEffect(() => { - const browserProvider = new ethers.BrowserProvider(window.ethereum!); - browserProvider.getSigner().then((signer) => { - const provider = new Provider({ - signer: new EthersSigner(signer), - storage: new BrowserStorage(), - contractFactory: new EthersContractFactory(signer), - }); + const getProvider = async () => { + const web3 = new Web3(window.ethereum); + await window.ethereum!.request({ method: 'eth_requestAccounts' }); + const accounts = await web3.eth.getAccounts(); + const account = accounts[0] as Address; + + const txParamsBuildFn = async () => { + const { baseFeePerGas } = await web3.eth.getBlock('pending'); + return { + from: account, + maxFeePerGas: `${BigInt(2) * baseFeePerGas!}`, + maxPriorityFeePerGas: `${baseFeePerGas! / BigInt(2)}`, + }; + }; + + return new Provider({ + signer: new Web3jsSigner(web3, account, txParamsBuildFn), + storage: new BrowserStorage(), + contractFactory: new Web3jsContractFactory(web3, txParamsBuildFn), + }); + }; + useEffect(() => { + getProvider().then((provider) => { setProvider(provider); }); }, []); + // useEffect(() => { + // const browserProvider = new ethers.BrowserProvider(window.ethereum!); + // browserProvider.getSigner().then((signer) => { + // const provider = new Provider({ + // signer: new EthersSigner(signer), + // storage: new BrowserStorage(), + // contractFactory: new EthersContractFactory(signer), + // }); + // + // setProvider(provider); + // }); + // }, []); + const handleSignClick = async () => { const authResult = await provider!.authenticate(); setAuth(authResult); @@ -42,10 +76,11 @@ export const ContractTesting = () => { .getContractFactory() .getContract('0xd10e3E8EbC4B55eAE572181be1554356Fb2a7767', JSON.stringify(storageAbi)); - // @ts-expect-error cast - const tx = await contract.call<{ hash: string }, string>('store', BigInt(value!)); + const tx = await contract.call('store', [ + BigInt(value!), + ]); setHash(`Wait for ${tx.hash} to be mined...`); - // @ts-expect-error hack + await tx.wait(); setValue(''); setHash(`Tx mined! Pls retieve the value`); diff --git a/examples/sandbox/src/components/signer-test.tsx b/examples/sandbox/src/components/signer-test.tsx index eaf6aaf..bd37174 100644 --- a/examples/sandbox/src/components/signer-test.tsx +++ b/examples/sandbox/src/components/signer-test.tsx @@ -1,4 +1,5 @@ -import { BrowserStorage, EthersContractFactory, EthersSigner, Provider } from '@ditto-network/core'; +import { BrowserStorage, Provider } from '@ditto-network/core'; +import { EthersContractFactory, EthersSigner } from '@ditto-network/ethers'; import { ethers } from 'ethers'; import { useState } from 'react'; diff --git a/examples/sandbox/src/components/vaults.tsx b/examples/sandbox/src/components/vaults.tsx index c023651..733cd9d 100644 --- a/examples/sandbox/src/components/vaults.tsx +++ b/examples/sandbox/src/components/vaults.tsx @@ -1,13 +1,7 @@ import React, { useEffect } from 'react'; import { ethers } from 'ethers'; -import { - BrowserStorage, - Chain, - EthersContractFactory, - EthersSigner, - Provider, - SmartWalletFactory, -} from '@ditto-network/core'; +import { BrowserStorage, Chain, Provider, SmartWalletFactory } from '@ditto-network/core'; +import { EthersSigner, EthersContractFactory } from '@ditto-network/ethers'; export const Vaults: React.FC = () => { const [provider, setProvider] = React.useState(null); diff --git a/examples/sandbox/src/components/workflows-web3js.tsx b/examples/sandbox/src/components/workflows-web3js.tsx new file mode 100644 index 0000000..b8df748 --- /dev/null +++ b/examples/sandbox/src/components/workflows-web3js.tsx @@ -0,0 +1,205 @@ +import { useEffect, useState } from 'react'; +import { + BaseApiError, + BrowserStorage, + Chain, + PriceTrigger, + Provider, + tokens, + WorkflowExecution, + WorkflowsFactory, + UniswapSwapActionCallDataBuilder, + Address, + TimeBasedTrigger, + TimeScale, +} from '@ditto-network/core'; +import { Web3jsContractFactory, Web3jsSigner } from '@ditto-network/web3.js'; +import { Web3 } from 'web3'; + +export const WorkflowsWeb3js = () => { + const [provider, setProvider] = useState(null); + const [workflowExecutions, setWorkflowExecutions] = useState([]); + + const getProvider = async () => { + const web3 = new Web3(window.ethereum); + await window.ethereum!.request({ method: 'eth_requestAccounts' }); + const accounts = await web3.eth.getAccounts(); + const account = accounts[0] as Address; + + console.log('Current account:', account); + + const txParamsBuildFn = async () => { + const { baseFeePerGas } = await web3.eth.getBlock('pending'); + + return { + from: account, + maxFeePerGas: `${BigInt(2) * baseFeePerGas!}`, + maxPriorityFeePerGas: `${baseFeePerGas! / BigInt(2)}`, + }; + }; + + return new Provider({ + signer: new Web3jsSigner(web3, account, txParamsBuildFn), + storage: new BrowserStorage(), + contractFactory: new Web3jsContractFactory(web3, txParamsBuildFn), + }); + }; + + useEffect(() => { + getProvider().then((provider) => { + setProvider(provider); + }); + }, []); + + const handleAuthClick = async () => { + await provider!.authenticate(); + }; + + const handleGetWorkflowsHistoryClick = async () => { + const workflowsFactory = new WorkflowsFactory(provider!); + + try { + const history: WorkflowExecution[] = await workflowsFactory.getHistory({ + limit: 10, + offset: 0, + }); + setWorkflowExecutions(history); + } catch (error) { + if (error instanceof BaseApiError && error.code === 401) { + alert('Please auth'); + return; + } + throw error; + } + }; + + const handleGetSingleWorkflowClick = async (id: string) => { + const workflowsFactory = new WorkflowsFactory(provider!); + const workflow = await workflowsFactory.getById(id); + + alert(JSON.stringify(workflow)); + }; + + const handleCreateWorkflowClick = async () => { + const workflowsFactory = new WorkflowsFactory(provider!); + + const commonConfig = { + chainId: 137, + recipient: '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919' as Address, + accountAddress: '0xAfe67Bfc16D0d7e2De988A1f89971aa3747221fF' as Address, + vaultAddress: '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919' as Address, + provider: provider!, + }; + + const wf = await workflowsFactory.create({ + name: 'test wf', + triggers: [ + // new PriceTrigger( + // { + // uniswapPoolFeeTier: 500, + // triggerAtPrice: '500000000000000000', + // priceMustBeHigherThan: true, + // fromToken: tokens.wrappedNative[Chain.Polygon], + // toToken: tokens.stableCoins[Chain.Polygon].USDT, + // }, + // commonConfig + // ), + new TimeBasedTrigger( + { + startAtTimestamp: Number((new Date().getTime() / 1000).toFixed(0)) + 60, + repeatTimes: 2, + cycle: { + frequency: 1, + scale: TimeScale.Minutes, + }, + }, + commonConfig + ), + ], + actions: [ + /* new UniswapSwapActionCallDataBuilder( + { + fromToken: tokens.wrapped[Chain.Polygon].WMATIC, + toToken: tokens.native[Chain.Polygon], + fromAmount: `123450000000000`, + slippagePercent: 0.1, + }, + commonConfig + ),*/ + + /* new UniswapSwapActionCallDataBuilder( + { + fromToken: tokens.native[Chain.Polygon], + toToken: tokens.stableCoins[Chain.Polygon].USDC, + fromAmount: `111110000000000`, + slippagePercent: 0.01, + }, + commonConfig + ),*/ + + new UniswapSwapActionCallDataBuilder( + { + fromToken: tokens.wrappedNative[Chain.Polygon], + toToken: tokens.stableCoins[Chain.Polygon].USDT, + fromAmount: `12345678900000`, + slippagePercent: 0.05, + providerStrategy: { + type: 'browser', + provider: (window as any).ethereum, + }, + }, + commonConfig + ), + ], + chainId: Chain.Polygon, + }); + + const hash = await wf.buildAndDeploy( + '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919', + '0xAfe67Bfc16D0d7e2De988A1f89971aa3747221fF' + ); + + console.log('hash', hash); + }; + + return ( +
+

Workflows sandbox

+ +
+ + + +
+ + {workflowExecutions && ( +
+ {workflowExecutions.map((execution) => ( + + ))} +
+ )} +
+ ); +}; diff --git a/examples/sandbox/src/components/workflows.tsx b/examples/sandbox/src/components/workflows.tsx index d3d0fb4..2a42ab9 100644 --- a/examples/sandbox/src/components/workflows.tsx +++ b/examples/sandbox/src/components/workflows.tsx @@ -3,15 +3,17 @@ import { BaseApiError, BrowserStorage, Chain, - EthersContractFactory, - EthersSigner, PriceTrigger, Provider, tokens, WorkflowExecution, WorkflowsFactory, UniswapSwapActionCallDataBuilder, + Address, + TimeBasedTrigger, + TimeScale, } from '@ditto-network/core'; +import { EthersContractFactory, EthersSigner } from '@ditto-network/ethers'; import { ethers } from 'ethers'; export const Workflows = () => { @@ -64,36 +66,36 @@ export const Workflows = () => { const commonConfig = { chainId: 137, - recipient: '0x8db38B3825D0C4EA7f826E7CA6D5e99F8f07D43a', - accountAddress: '0xAfe67Bfc16D0d7e2De988A1f89971aa3747221fF', - vaultAddress: '0x8db38B3825D0C4EA7f826E7CA6D5e99F8f07D43a', + recipient: '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919' as Address, + accountAddress: '0xAfe67Bfc16D0d7e2De988A1f89971aa3747221fF' as Address, + vaultAddress: '0xb1Ec673122AC9eb2f3efb51c62911D16d3a29919' as Address, provider: provider!, }; const wf = await workflowsFactory.create({ name: 'test wf', triggers: [ - new PriceTrigger( - { - uniswapPoolFeeTier: 500, - triggerAtPrice: '500000000000000000', - priceMustBeHigherThan: true, - fromToken: tokens.wrappedNative[Chain.Polygon], - toToken: tokens.stableCoins[Chain.Polygon].USDT, - }, - commonConfig - ), - // new TimeBasedTrigger( + // new PriceTrigger( // { - // startAtTimestamp: Number((new Date().getTime() / 1000).toFixed(0)) + 60, - // repeatTimes: 2, - // cycle: { - // frequency: 1, - // scale: TimeScale.Minutes, - // }, + // uniswapPoolFeeTier: 500, + // triggerAtPrice: '500000000000000000', + // priceMustBeHigherThan: true, + // fromToken: tokens.wrappedNative[Chain.Polygon], + // toToken: tokens.stableCoins[Chain.Polygon].USDT, // }, // commonConfig // ), + new TimeBasedTrigger( + { + startAtTimestamp: Number((new Date().getTime() / 1000).toFixed(0)) + 60, + repeatTimes: 2, + cycle: { + frequency: 1, + scale: TimeScale.Minutes, + }, + }, + commonConfig + ), ], actions: [ /* new UniswapSwapActionCallDataBuilder( diff --git a/examples/sandbox/src/main.tsx b/examples/sandbox/src/main.tsx index bebbb6d..ecc7f97 100644 --- a/examples/sandbox/src/main.tsx +++ b/examples/sandbox/src/main.tsx @@ -9,6 +9,7 @@ import { SignerTest } from './components/signer-test'; import { Workflows } from './components/workflows'; import { Navbar } from './navbar'; import { Vaults } from './components/vaults'; +import { WorkflowsWeb3js } from '@/components/workflows-web3js'; const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render( @@ -36,6 +37,7 @@ root.render( } /> } /> } /> + } /> } /> diff --git a/package-lock.json b/package-lock.json index 752b382..3c64d9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,8 @@ "@commitlint/config-conventional": "^19.2.2", "@commitlint/cz-commitlint": "^19.2.0", "@ditto-network/core": "file:packages/core", + "@ditto-network/ethers": "file:packages/ethers", + "@ditto-network/web3.js": "file:packages/web3js", "@nx/esbuild": "18.2.3", "@nx/eslint": "18.1.3", "@nx/eslint-plugin": "18.1.3", @@ -69,7 +71,8 @@ "verdaccio": "^5.0.4", "vite": "~5.0.0", "vite-plugin-dts": "~2.3.0", - "vitest": "^1.3.1" + "vitest": "^1.3.1", + "web3": "4.8.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2968,6 +2971,14 @@ "resolved": "packages/core", "link": true }, + "node_modules/@ditto-network/ethers": { + "resolved": "packages/ethers", + "link": true + }, + "node_modules/@ditto-network/web3.js": { + "resolved": "packages/web3js", + "link": true + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -3441,6 +3452,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@ethersproject/abi": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", @@ -5311,6 +5334,30 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/hashes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", @@ -8469,7 +8516,6 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", - "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -9660,6 +9706,15 @@ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -11397,6 +11452,21 @@ "deprecated": "Use your platform's native atob() and btoa() methods instead", "dev": true }, + "node_modules/abitype": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.7.1.tgz", + "integrity": "sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ==", + "dev": true, + "peerDependencies": { + "typescript": ">=4.9.4", + "zod": "^3 >=3.19.1" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -13775,6 +13845,18 @@ "typescript": ">=4" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -18281,6 +18363,21 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -18610,6 +18707,15 @@ "resolved": "https://registry.npmjs.org/isnumber/-/isnumber-1.0.0.tgz", "integrity": "sha512-JLiSz/zsZcGFXPrB4I/AGBvtStkt+8QmksyZBZnVXnnK9XdTEyz0tX8CRYljtwYDuIuZzih6DpHQdi+3Q6zHPw==" }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true, + "peerDependencies": { + "ws": "*" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -24921,8 +25027,7 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "peer": true + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -26499,6 +26604,19 @@ "requires-port": "^1.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -27196,6 +27314,496 @@ "defaults": "^1.0.3" } }, + "node_modules/web3": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-4.8.0.tgz", + "integrity": "sha512-kQSF2NlHk8yjS3SRiJW3S+U5ibkEmVRhB4/GYsVwGvdAkFC2b+EIE1Ob7J56OmqW9VBZgkx1+SuWqo5JTIJSYQ==", + "dev": true, + "dependencies": { + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.6.0", + "web3-eth-abi": "^4.2.1", + "web3-eth-accounts": "^4.1.2", + "web3-eth-contract": "^4.4.0", + "web3-eth-ens": "^4.2.0", + "web3-eth-iban": "^4.0.7", + "web3-eth-personal": "^4.0.8", + "web3-net": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.2.0", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-core": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.2.tgz", + "integrity": "sha512-uIMVd/j4BgOnwfpY8ZT+QKubOyM4xohEhFZXz9xB8wimXWMMlYVlIK/TbfHqFolS9uOerdSGhsMbcK9lETae8g==", + "dev": true, + "dependencies": { + "web3-errors": "^1.1.4", + "web3-eth-accounts": "^4.1.0", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.1", + "web3-utils": "^4.1.0", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + }, + "optionalDependencies": { + "web3-providers-ipc": "^4.0.7" + } + }, + "node_modules/web3-errors": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web3-errors/-/web3-errors-1.1.4.tgz", + "integrity": "sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==", + "dev": true, + "dependencies": { + "web3-types": "^1.3.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.6.0.tgz", + "integrity": "sha512-8KtxlGsomovoFULqEpfixgmCpaJ2YIJGxbXUfezh2coXHjVgEopQhARYtKGClyV5kkdCIqwHS8Gvsm6TVNqH6Q==", + "dev": true, + "dependencies": { + "setimmediate": "^1.0.5", + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth-abi": "^4.2.1", + "web3-eth-accounts": "^4.1.2", + "web3-net": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.2.0", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-4.2.1.tgz", + "integrity": "sha512-IE91WUhhiDpBtbkl/DHUoZz7z7T5FXvl3zPLkrxT+dNlOT+wni+US/67jQCLvJRbqf9ApQ26lVYry0bovFgyqA==", + "dev": true, + "dependencies": { + "abitype": "0.7.1", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-4.1.2.tgz", + "integrity": "sha512-y0JynDeTDnclyuE9mShXLeEj+BCrPHxPHOyPCgTchUBQsALF9+0OhP7WiS3IqUuu0Hle5bjG2f5ddeiPtNEuLg==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "crc-32": "^1.2.2", + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-eth-accounts/node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-eth-accounts/node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-eth-accounts/node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dev": true, + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/web3-eth-contract": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-4.4.0.tgz", + "integrity": "sha512-pZ/w6Lb6ZDUUs7f5GCKXiHDAGGvt2tdwiHkvgmQTRnq9b0MEsUpteDyPYspHxKzQWLgbeK37jPb8zbQe4kE/Hg==", + "dev": true, + "dependencies": { + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.6.0", + "web3-eth-abi": "^4.2.1", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-4.2.0.tgz", + "integrity": "sha512-qYj34te2UctoObt8rlEIY/t2MuTMiMiiHhO2JAHRGqSLCQ7b8DM3RpvkiiSB0N0ZyEn+CetZqJCTYb8DNKBS/g==", + "dev": true, + "dependencies": { + "@adraffy/ens-normalize": "^1.8.8", + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.5.0", + "web3-eth-contract": "^4.3.0", + "web3-net": "^4.0.7", + "web3-types": "^1.5.0", + "web3-utils": "^4.2.2", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-4.0.7.tgz", + "integrity": "sha512-8weKLa9KuKRzibC87vNLdkinpUE30gn0IGY027F8doeJdcPUfsa4IlBgNC4k4HLBembBB2CTU0Kr/HAOqMeYVQ==", + "dev": true, + "dependencies": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-4.0.8.tgz", + "integrity": "sha512-sXeyLKJ7ddQdMxz1BZkAwImjqh7OmKxhXoBNF3isDmD4QDpMIwv/t237S3q4Z0sZQamPa/pHebJRWVuvP8jZdw==", + "dev": true, + "dependencies": { + "web3-core": "^4.3.0", + "web3-eth": "^4.3.1", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-net": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-4.0.7.tgz", + "integrity": "sha512-SzEaXFrBjY25iQGk5myaOfO9ZyfTwQEa4l4Ps4HDNVMibgZji3WPzpjq8zomVHMwi8bRp6VV7YS71eEsX7zLow==", + "dev": true, + "dependencies": { + "web3-core": "^4.3.0", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-4.1.0.tgz", + "integrity": "sha512-6qRUGAhJfVQM41E5t+re5IHYmb5hSaLc02BE2MaRQsz2xKA6RjmHpOA5h/+ojJxEpI9NI2CrfDKOAgtJfoUJQg==", + "dev": true, + "dependencies": { + "cross-fetch": "^4.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-http/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/web3-providers-ipc": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-4.0.7.tgz", + "integrity": "sha512-YbNqY4zUvIaK2MHr1lQFE53/8t/ejHtJchrWn9zVbFMGXlTsOAbNoIoZWROrg1v+hCBvT2c9z8xt7e/+uz5p1g==", + "dev": true, + "optional": true, + "dependencies": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-4.0.7.tgz", + "integrity": "sha512-n4Dal9/rQWjS7d6LjyEPM2R458V8blRm0eLJupDEJOOIBhGYlxw5/4FthZZ/cqB7y/sLVi7K09DdYx2MeRtU5w==", + "dev": true, + "dependencies": { + "@types/ws": "8.5.3", + "isomorphic-ws": "^5.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "ws": "^8.8.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-rpc-methods": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web3-rpc-methods/-/web3-rpc-methods-1.2.0.tgz", + "integrity": "sha512-CWJ/g4I4WyYvLkf21wCZAehdhU/VjX/OAPHnqF5/FPDJlogOsOnGXHqi1Z5AP+ocdt395PNubd8jyMMJoYGSBA==", + "dev": true, + "dependencies": { + "web3-core": "^4.3.2", + "web3-types": "^1.5.0", + "web3-validator": "^2.0.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-types": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.6.0.tgz", + "integrity": "sha512-qgOtADqlD5hw+KPKBUGaXAcdNLL0oh6qTeVgXwewCfbL/lG9R+/GrgMQB1gbTJ3cit8hMwtH8KX2Em6OwO0HRw==", + "dev": true, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-utils": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.3.tgz", + "integrity": "sha512-m5plKTC2YtQntHITQRyIePw52UVP1IrShhmA2FACtn4zmc5ADmrXOlQWiPzxFP/18eRJsAaUAw2+CQn1u4WPxQ==", + "dev": true, + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "eventemitter3": "^5.0.1", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dev": true, + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/web3-utils/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/web3-validator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/web3-validator/-/web3-validator-2.0.5.tgz", + "integrity": "sha512-2gLOSW8XqEN5pw5jVUm20EB7A8SbQiekpAtiI0JBmCIV0a2rp97v8FgWY5E3UEqnw5WFfEqvcDVW92EyynDTyQ==", + "dev": true, + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "util": "^0.12.5", + "web3-errors": "^1.1.4", + "web3-types": "^1.5.0", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-validator/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-validator/node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-validator/node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-validator/node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dev": true, + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -27610,7 +28218,17 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/zod": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.0.tgz", + "integrity": "sha512-OFLT+LTocvabn6q76BTwVB0hExEBS0IduTr3cqZyMqEDbOnYmcU+y0tUAYbND4uwclpBGi4I4UUBGzylWpjLGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "packages/core": { + "name": "@ditto-network/core", "version": "0.0.4", "dev": true, "dependencies": { @@ -27622,6 +28240,42 @@ "fetch-ponyfill": "7.1.0", "rambda": "9.2.0" } + }, + "packages/ethers": { + "name": "@ditto-network/ethers", + "version": "0.0.1", + "dev": true, + "dependencies": { + "@ditto-network/core": "file:../core", + "ethers": "6.11.1", + "tslib": "^2.3.0" + } + }, + "packages/ethers/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "dev": true + }, + "packages/web3.js": { + "extraneous": true + }, + "packages/web3js": { + "name": "@ditto-network/web3.js", + "version": "0.0.1", + "dev": true, + "dependencies": { + "@ditto-network/core": "file:../core", + "tslib": "^2.3.0", + "web3": "4.8.0", + "web3-types": "1.6.0" + } + }, + "packages/web3js/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "dev": true } } } diff --git a/package.json b/package.json index 54bf524..757661f 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,10 @@ "vite": "~5.0.0", "vite-plugin-dts": "~2.3.0", "vitest": "^1.3.1", - "@ditto-network/core": "file:packages/core" + "@ditto-network/core": "file:packages/core", + "@ditto-network/ethers": "file:packages/ethers", + "@ditto-network/web3.js": "file:packages/web3js", + "web3": "4.8.0" }, "resolutions": { "ethers": "^6.11.1" diff --git a/packages/core/README.md b/packages/core/README.md index 98c3d9c..e9a8595 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -109,7 +109,7 @@ const { hash } = await contract.call('store', [12345n] // wallet will be opened, you should write tx and send to blockchain and wait for tx mining // read method -const storedNumber = await contract.call('retrieve', [null]) +const storedNumber = await contract.call('retrieve', []) // stored number is 12345n ``` diff --git a/packages/core/src/lib/contracts/types.ts b/packages/core/src/lib/contracts/types.ts index e00b804..b976828 100644 --- a/packages/core/src/lib/contracts/types.ts +++ b/packages/core/src/lib/contracts/types.ts @@ -1,4 +1,5 @@ import { Address, Maybe } from '../types'; +import { JSONObject } from '../network/api-client/types'; export interface ContractFactory { getContract(address: Address, abi: string): T; @@ -6,8 +7,12 @@ export interface ContractFactory(method: string, ...params: P): Promise; - estimateGas(method: string, params: unknown[]): Promise; + call( + method: string, + params?: P, + additionalTxParams?: JSONObject + ): Promise; + estimateGas(method: string, params: unknown[], additionalTxParams?: JSONObject): Promise; } export interface DittoContractInterface { @@ -16,3 +21,5 @@ export interface DittoContractInterface { } export class DittoContractNotInitializedError extends Error {} + +export class DittoContractMethodNotFoundError extends Error {} diff --git a/packages/core/src/lib/ditto-sdk.ts b/packages/core/src/lib/ditto-sdk.ts index 2993392..4c96c82 100644 --- a/packages/core/src/lib/ditto-sdk.ts +++ b/packages/core/src/lib/ditto-sdk.ts @@ -19,7 +19,10 @@ import { wrappedNativeTokens } from './blockchain/tokens/wrappedNative'; import { UniswapSwapActionCallDataBuilder } from './workflow/actions'; import { DittoSigner } from './signer/types'; import type { DittoContractInterface, ContractFactory, DittoContract } from './contracts/types'; -import { DittoContractNotInitializedError } from './contracts/types'; +import { + DittoContractNotInitializedError, + DittoContractMethodNotFoundError, +} from './contracts/types'; import type { Address, Maybe, @@ -28,6 +31,7 @@ import type { Optional, WalletAddress, Transaction, + MutationTransactionReturnType, } from './types'; export { @@ -47,6 +51,7 @@ export { UniswapSwapActionCallDataBuilder, TimeBasedTrigger, DittoContractNotInitializedError, + DittoContractMethodNotFoundError, }; export type { @@ -68,4 +73,5 @@ export type { Optional, WalletAddress, Transaction, + MutationTransactionReturnType, }; diff --git a/packages/core/src/lib/network/api-client/types.ts b/packages/core/src/lib/network/api-client/types.ts index 700d15a..19a9d06 100644 --- a/packages/core/src/lib/network/api-client/types.ts +++ b/packages/core/src/lib/network/api-client/types.ts @@ -1,6 +1,6 @@ export type AuthNonce = string; -export type JSONBody = string | number | boolean | JSONObject; +export type JSONBody = string | number | boolean | bigint | JSONObject; export interface JSONObject { [x: string]: JSONBody; diff --git a/packages/core/src/lib/signer/types.ts b/packages/core/src/lib/signer/types.ts index dcc4fe9..d2ef303 100644 --- a/packages/core/src/lib/signer/types.ts +++ b/packages/core/src/lib/signer/types.ts @@ -1,10 +1,9 @@ -import { Address, Transaction, TxHash, WalletAddress } from '../types'; -import { ethers } from 'ethers'; +import { Address, MutationTransactionReturnType, Transaction } from '../types'; +import { JSONObject } from '../network/api-client/types'; export interface DittoSigner { - getRawSigner(): ethers.Signer; - getAddress(): Promise; - sendTransaction(tx: Transaction): Promise<{ hash: TxHash; wait: () => Promise }>; + getAddress(): Promise
; + sendTransaction(tx: Transaction & JSONObject): Promise; signMessage(message: string): Promise; getBalance(address: Address): Promise; } diff --git a/packages/core/src/lib/types.ts b/packages/core/src/lib/types.ts index d9ac93a..f039bcf 100644 --- a/packages/core/src/lib/types.ts +++ b/packages/core/src/lib/types.ts @@ -7,6 +7,11 @@ export type Maybe = Optional | Nullable; export type WalletAddress = `0x${string}`; export type Address = `0x${string}`; -export type Transaction = Partial>; +export type Transaction = Partial< + Pick & { from?: Address } +> & + Record; export type TxHash = string; + +export type MutationTransactionReturnType = { hash: TxHash; wait: () => Promise }; diff --git a/packages/core/src/lib/vaults/smart-wallet-factory.ts b/packages/core/src/lib/vaults/smart-wallet-factory.ts index 9a37540..03be6b7 100644 --- a/packages/core/src/lib/vaults/smart-wallet-factory.ts +++ b/packages/core/src/lib/vaults/smart-wallet-factory.ts @@ -8,7 +8,7 @@ import { SmartWalletVersion } from './smart-wallet/types'; import { SmartWalletCreationError } from './smart-wallet/errors/SmartWalletCreationError'; import { config } from '../config/config'; import { Chain } from '../blockchain/chains/types'; -import { Address, Maybe } from '../types'; +import { Address, Maybe, MutationTransactionReturnType } from '../types'; import { DittoContract } from '../contracts/types'; export class SmartWalletFactory implements Factory { @@ -29,11 +29,10 @@ export class SmartWalletFactory implements Factory { throw new Error(`Vault with id=${id} already exists`); } - return this.getContract(chainId).call<{ wait: () => Promise }, unknown[]>( - 'deploy', + return this.getContract(chainId).call('deploy', [ version, - id - ); + id, + ]); } public async list(chainId: Chain): Promise { @@ -109,11 +108,10 @@ export class SmartWalletFactory implements Factory { chainId: Chain, vaultId: number ): Promise
{ - return this.getContract(chainId).call( - 'predictDeterministicVaultAddress', + return this.getContract(chainId).call('predictDeterministicVaultAddress', [ accountAddress, - vaultId - ); + vaultId, + ]); } private async fetchFirstVault(chainId: Chain): Promise> { diff --git a/packages/core/src/lib/vaults/smart-wallet/smart-wallet.ts b/packages/core/src/lib/vaults/smart-wallet/smart-wallet.ts index a6d52af..6f508d0 100644 --- a/packages/core/src/lib/vaults/smart-wallet/smart-wallet.ts +++ b/packages/core/src/lib/vaults/smart-wallet/smart-wallet.ts @@ -7,7 +7,7 @@ import { config } from '../../config/config'; import { SmartWalletNotDeployedError } from './errors/SmartWalletNotDeployedError'; import { Chain } from '../../blockchain/chains/types'; import { isAddressesEqual } from '../../blockchain/tokens/utils'; -import { Address, Maybe, Nullable } from '../../types'; +import { Address, Maybe, MutationTransactionReturnType, Nullable } from '../../types'; import { DittoContract } from '../../contracts/types'; export class SmartWallet implements ISmartWallet { @@ -67,11 +67,10 @@ export class SmartWallet implements ISmartWallet { throw new SmartWalletWithIdExistsError(this.id); } - await this.vaultFactoryContract.call<{ wait: () => Promise }, unknown[]>( - 'deploy', + await this.vaultFactoryContract.call('deploy', [ this.version, - this.id - ); + this.id, + ]); return true; } diff --git a/packages/core/src/lib/workflow/factory.ts b/packages/core/src/lib/workflow/factory.ts index 0e4fd80..394ee18 100644 --- a/packages/core/src/lib/workflow/factory.ts +++ b/packages/core/src/lib/workflow/factory.ts @@ -51,7 +51,7 @@ export class WorkflowsFactory implements IWorkflowFactory { .getContractFactory() .getContract(address, JSON.stringify(VaultABI)); - const tx = await vaultContract.call<{ hash: string }, [number]>('deactivateWorkflow', id); + const tx = await vaultContract.call<{ hash: string }, [number]>('deactivateWorkflow', [id]); return tx.hash; } } diff --git a/packages/core/src/lib/workflow/triggers/price-trigger.ts b/packages/core/src/lib/workflow/triggers/price-trigger.ts index a679b29..dab7faf 100644 --- a/packages/core/src/lib/workflow/triggers/price-trigger.ts +++ b/packages/core/src/lib/workflow/triggers/price-trigger.ts @@ -107,14 +107,13 @@ export class PriceTrigger implements CallDataBuilder { .getContractFactory() .getContract(oracleAddress, JSON.stringify(DittoOracleABI)); - const targetRateBigInt = await oracleContract.call( - 'consult', + const targetRateBigInt = await oracleContract.call('consult', [ this.config.toToken.address, this.config.triggerAtPrice, this.config.fromToken.address, this.config.uniswapPoolFeeTier, - uniswapFactoryAddress - ); + uniswapFactoryAddress, + ]); const targetRate = targetRateBigInt.toString(); diff --git a/packages/ethers/package-lock.json b/packages/ethers/package-lock.json index 763c0a7..f40f9e7 100644 --- a/packages/ethers/package-lock.json +++ b/packages/ethers/package-lock.json @@ -10,10 +10,11 @@ "dependencies": { "@ditto-network/core": "file:../core", "ethers": "6.11.1", - "tslib": "^2.3.0" + "tslib": "2.3.0" } }, "../core": { + "name": "@ditto-network/core", "version": "0.0.4", "dependencies": { "@uniswap/sdk-core": "^3.2.6", @@ -99,9 +100,9 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "node_modules/ws": { "version": "8.5.0", diff --git a/packages/ethers/src/lib/contract/ethers-contract.ts b/packages/ethers/src/lib/contract/ethers-contract.ts index 1e9fa62..577ae55 100644 --- a/packages/ethers/src/lib/contract/ethers-contract.ts +++ b/packages/ethers/src/lib/contract/ethers-contract.ts @@ -16,14 +16,18 @@ export class EthersContract implements DittoContract { this.contractInterface = new EthersContractInterface(abi); } - public async call(method: string, ...params: P): Promise { + public async call( + method: string, + params: P = [] as unknown as P + ): Promise { if (!this.nativeContract) { throw new DittoContractNotInitializedError(); } - const result = params - ? await this.nativeContract[method](...params) - : await this.nativeContract[method](); + const result = + params.length > 0 + ? await this.nativeContract[method](...params) + : await this.nativeContract[method](); return result as R; } diff --git a/packages/ethers/src/lib/signer/ethers-signer.ts b/packages/ethers/src/lib/signer/ethers-signer.ts index ddffc9e..c36df1c 100644 --- a/packages/ethers/src/lib/signer/ethers-signer.ts +++ b/packages/ethers/src/lib/signer/ethers-signer.ts @@ -1,5 +1,10 @@ -import { Signer, Transaction, BrowserProvider, Wallet } from 'ethers'; -import { Address, TxHash, DittoSigner } from '@ditto-network/core'; +import { Signer, Wallet } from 'ethers'; +import { + Address, + DittoSigner, + Transaction, + MutationTransactionReturnType, +} from '@ditto-network/core'; export class EthersSigner implements DittoSigner { constructor(private readonly ethersSigner: Signer | Wallet) {} @@ -9,9 +14,7 @@ export class EthersSigner implements DittoSigner { return address as Address; } - public async sendTransaction( - tx: Transaction - ): Promise<{ hash: TxHash; wait: () => Promise }> { + public async sendTransaction(tx: Transaction): Promise { const { hash, wait } = await this.ethersSigner.sendTransaction(tx); return { hash, wait }; } @@ -25,9 +28,7 @@ export class EthersSigner implements DittoSigner { } public async getBalance(address: Address): Promise { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - const balance = await new BrowserProvider(window.ethereum).getBalance(address); + const balance = await this.ethersSigner.provider!.getBalance(address); return balance.toString(); } } diff --git a/packages/web3js/.eslintignore b/packages/web3js/.eslintignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/packages/web3js/.eslintignore @@ -0,0 +1 @@ +node_modules/ diff --git a/packages/web3js/.eslintrc.json b/packages/web3js/.eslintrc.json new file mode 100644 index 0000000..a6175d5 --- /dev/null +++ b/packages/web3js/.eslintrc.json @@ -0,0 +1,30 @@ +{ + "extends": ["../../.eslintrc.base.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "ignoredFiles": ["{projectRoot}/vite.config.{js,ts,mjs,mts}"] + } + ] + } + } + ] +} diff --git a/packages/web3js/README.md b/packages/web3js/README.md new file mode 100644 index 0000000..5fdcd87 --- /dev/null +++ b/packages/web3js/README.md @@ -0,0 +1,69 @@ +# @ditto-network/web3.js + +Web3.js adapter for Ditto Network SDK. + +## How to use +### Node.js version + +```typescript +const web3 = new Web3(process.env.INFURA_API_URL!); + +// accounts initialization +const accounts = web3.eth.accounts.wallet.add(`0x${process.env.PRIVATE_KEY!}`); +const account = accounts[0].address! as Address; + +// use this function if you want to pass some params for all txs, +// (calc maxFeePerGas and maxPriorityFeePerGas based on the pending block, for example) +// sdk doesn't calculate these values for you +// you able to pass additional params to signer.sendTransaction / contract.call for every call, +// but if you want to setup it once, you can do it here only once +const txParamsDecorator = async () => { + const { baseFeePerGas } = await web3.eth.getBlock('pending'); + + return { + maxFeePerGas: `${BigInt(2) * baseFeePerGas!}`, + maxPriorityFeePerGas: `${baseFeePerGas! / BigInt(2)}`, + }; +}; + +const dittoProvider = new Provider({ + signer: new Web3jsSigner(web3, account, txParamsDecorator), + storage: new InMemoryStorage(), + contractFactory: new Web3jsContractFactory(web3, txParamsDecorator), +}); +``` + +### Browser version + +```typescript +const web3 = new Web3(window.ethereum); + +// accounts initialization +await window.ethereum!.request({ method: 'eth_requestAccounts' }); +const accounts = await web3.eth.getAccounts(); +const account = accounts[0] as Address; + +const txParamsDecorator = async () => { + const { baseFeePerGas } = await web3.eth.getBlock('pending'); + + return { + from: account, + maxFeePerGas: `${BigInt(2) * baseFeePerGas!}`, + maxPriorityFeePerGas: `${baseFeePerGas! / BigInt(2)}`, + }; +}; + +const dittoProvider = new Provider({ + signer: new Web3jsSigner(web3, account, txParamsDecorator), + storage: new BrowserStorage(), + contractFactory: new Web3jsContractFactory(web3, txParamsDecorator), +}); +``` + +## Building + +Run `nx build web3js` to build the library. + +## Running unit tests + +Run `nx test web3js` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/packages/web3js/package-lock.json b/packages/web3js/package-lock.json new file mode 100644 index 0000000..7dd02bf --- /dev/null +++ b/packages/web3js/package-lock.json @@ -0,0 +1,859 @@ +{ + "name": "@ditto-network/web3.js", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@ditto-network/web3.js", + "version": "0.0.1", + "dependencies": { + "@ditto-network/core": "file:../core", + "tslib": "2.3.0", + "web3": "4.8.0" + } + }, + "../core": { + "name": "@ditto-network/core", + "version": "0.0.4", + "dependencies": { + "@uniswap/sdk-core": "^3.2.6", + "@uniswap/smart-order-router": "3.16.26", + "@uniswap/v3-sdk": "^3.10.0", + "ethers": "6.11.1", + "ethers5": "npm:ethers@5.7.1", + "fetch-ponyfill": "7.1.0", + "rambda": "9.2.0" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" + }, + "node_modules/@ditto-network/core": { + "resolved": "../core", + "link": true + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/base": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", + "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abitype": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.7.1.tgz", + "integrity": "sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ==", + "peerDependencies": { + "typescript": ">=4.9.4", + "zod": "^3 >=3.19.1" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/web3": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-4.8.0.tgz", + "integrity": "sha512-kQSF2NlHk8yjS3SRiJW3S+U5ibkEmVRhB4/GYsVwGvdAkFC2b+EIE1Ob7J56OmqW9VBZgkx1+SuWqo5JTIJSYQ==", + "dependencies": { + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.6.0", + "web3-eth-abi": "^4.2.1", + "web3-eth-accounts": "^4.1.2", + "web3-eth-contract": "^4.4.0", + "web3-eth-ens": "^4.2.0", + "web3-eth-iban": "^4.0.7", + "web3-eth-personal": "^4.0.8", + "web3-net": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.2.0", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-core": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.2.tgz", + "integrity": "sha512-uIMVd/j4BgOnwfpY8ZT+QKubOyM4xohEhFZXz9xB8wimXWMMlYVlIK/TbfHqFolS9uOerdSGhsMbcK9lETae8g==", + "dependencies": { + "web3-errors": "^1.1.4", + "web3-eth-accounts": "^4.1.0", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.1", + "web3-utils": "^4.1.0", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + }, + "optionalDependencies": { + "web3-providers-ipc": "^4.0.7" + } + }, + "node_modules/web3-errors": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web3-errors/-/web3-errors-1.1.4.tgz", + "integrity": "sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==", + "dependencies": { + "web3-types": "^1.3.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.6.0.tgz", + "integrity": "sha512-8KtxlGsomovoFULqEpfixgmCpaJ2YIJGxbXUfezh2coXHjVgEopQhARYtKGClyV5kkdCIqwHS8Gvsm6TVNqH6Q==", + "dependencies": { + "setimmediate": "^1.0.5", + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth-abi": "^4.2.1", + "web3-eth-accounts": "^4.1.2", + "web3-net": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.2.0", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-4.2.1.tgz", + "integrity": "sha512-IE91WUhhiDpBtbkl/DHUoZz7z7T5FXvl3zPLkrxT+dNlOT+wni+US/67jQCLvJRbqf9ApQ26lVYry0bovFgyqA==", + "dependencies": { + "abitype": "0.7.1", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-4.1.2.tgz", + "integrity": "sha512-y0JynDeTDnclyuE9mShXLeEj+BCrPHxPHOyPCgTchUBQsALF9+0OhP7WiS3IqUuu0Hle5bjG2f5ddeiPtNEuLg==", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "crc-32": "^1.2.2", + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-contract": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-4.4.0.tgz", + "integrity": "sha512-pZ/w6Lb6ZDUUs7f5GCKXiHDAGGvt2tdwiHkvgmQTRnq9b0MEsUpteDyPYspHxKzQWLgbeK37jPb8zbQe4kE/Hg==", + "dependencies": { + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.6.0", + "web3-eth-abi": "^4.2.1", + "web3-types": "^1.6.0", + "web3-utils": "^4.2.3", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-4.2.0.tgz", + "integrity": "sha512-qYj34te2UctoObt8rlEIY/t2MuTMiMiiHhO2JAHRGqSLCQ7b8DM3RpvkiiSB0N0ZyEn+CetZqJCTYb8DNKBS/g==", + "dependencies": { + "@adraffy/ens-normalize": "^1.8.8", + "web3-core": "^4.3.2", + "web3-errors": "^1.1.4", + "web3-eth": "^4.5.0", + "web3-eth-contract": "^4.3.0", + "web3-net": "^4.0.7", + "web3-types": "^1.5.0", + "web3-utils": "^4.2.2", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-4.0.7.tgz", + "integrity": "sha512-8weKLa9KuKRzibC87vNLdkinpUE30gn0IGY027F8doeJdcPUfsa4IlBgNC4k4HLBembBB2CTU0Kr/HAOqMeYVQ==", + "dependencies": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-4.0.8.tgz", + "integrity": "sha512-sXeyLKJ7ddQdMxz1BZkAwImjqh7OmKxhXoBNF3isDmD4QDpMIwv/t237S3q4Z0sZQamPa/pHebJRWVuvP8jZdw==", + "dependencies": { + "web3-core": "^4.3.0", + "web3-eth": "^4.3.1", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-net": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-4.0.7.tgz", + "integrity": "sha512-SzEaXFrBjY25iQGk5myaOfO9ZyfTwQEa4l4Ps4HDNVMibgZji3WPzpjq8zomVHMwi8bRp6VV7YS71eEsX7zLow==", + "dependencies": { + "web3-core": "^4.3.0", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-4.1.0.tgz", + "integrity": "sha512-6qRUGAhJfVQM41E5t+re5IHYmb5hSaLc02BE2MaRQsz2xKA6RjmHpOA5h/+ojJxEpI9NI2CrfDKOAgtJfoUJQg==", + "dependencies": { + "cross-fetch": "^4.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-4.0.7.tgz", + "integrity": "sha512-YbNqY4zUvIaK2MHr1lQFE53/8t/ejHtJchrWn9zVbFMGXlTsOAbNoIoZWROrg1v+hCBvT2c9z8xt7e/+uz5p1g==", + "optional": true, + "dependencies": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-4.0.7.tgz", + "integrity": "sha512-n4Dal9/rQWjS7d6LjyEPM2R458V8blRm0eLJupDEJOOIBhGYlxw5/4FthZZ/cqB7y/sLVi7K09DdYx2MeRtU5w==", + "dependencies": { + "@types/ws": "8.5.3", + "isomorphic-ws": "^5.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "ws": "^8.8.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-rpc-methods": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web3-rpc-methods/-/web3-rpc-methods-1.2.0.tgz", + "integrity": "sha512-CWJ/g4I4WyYvLkf21wCZAehdhU/VjX/OAPHnqF5/FPDJlogOsOnGXHqi1Z5AP+ocdt395PNubd8jyMMJoYGSBA==", + "dependencies": { + "web3-core": "^4.3.2", + "web3-types": "^1.5.0", + "web3-validator": "^2.0.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-types": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.6.0.tgz", + "integrity": "sha512-qgOtADqlD5hw+KPKBUGaXAcdNLL0oh6qTeVgXwewCfbL/lG9R+/GrgMQB1gbTJ3cit8hMwtH8KX2Em6OwO0HRw==", + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-utils": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.3.tgz", + "integrity": "sha512-m5plKTC2YtQntHITQRyIePw52UVP1IrShhmA2FACtn4zmc5ADmrXOlQWiPzxFP/18eRJsAaUAw2+CQn1u4WPxQ==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "eventemitter3": "^5.0.1", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-validator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/web3-validator/-/web3-validator-2.0.5.tgz", + "integrity": "sha512-2gLOSW8XqEN5pw5jVUm20EB7A8SbQiekpAtiI0JBmCIV0a2rp97v8FgWY5E3UEqnw5WFfEqvcDVW92EyynDTyQ==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "util": "^0.12.5", + "web3-errors": "^1.1.4", + "web3-types": "^1.5.0", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.0.tgz", + "integrity": "sha512-OFLT+LTocvabn6q76BTwVB0hExEBS0IduTr3cqZyMqEDbOnYmcU+y0tUAYbND4uwclpBGi4I4UUBGzylWpjLGA==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/packages/web3js/package.json b/packages/web3js/package.json new file mode 100644 index 0000000..fd61246 --- /dev/null +++ b/packages/web3js/package.json @@ -0,0 +1,13 @@ +{ + "name": "@ditto-network/web3.js", + "version": "0.0.1", + "dependencies": { + "@ditto-network/core": "file:../core", + "tslib": "^2.3.0", + "web3": "4.8.0", + "web3-types": "1.6.0" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/packages/web3js/project.json b/packages/web3js/project.json new file mode 100644 index 0000000..c3682c9 --- /dev/null +++ b/packages/web3js/project.json @@ -0,0 +1,32 @@ +{ + "name": "web3js", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/web3js/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/web3js", + "main": "packages/web3js/src/index.ts", + "tsConfig": "packages/web3js/tsconfig.lib.json", + "assets": ["packages/web3js/*.md"] + } + }, + "nx-release-publish": { + "options": { + "packageRoot": "dist/{projectRoot}" + } + } + }, + "tags": [], + "release": { + "version": { + "generatorOptions": { + "packageRoot": "dist/{projectRoot}", + "currentVersionResolver": "git-tag" + } + } + } +} diff --git a/packages/web3js/src/index.ts b/packages/web3js/src/index.ts new file mode 100644 index 0000000..613c417 --- /dev/null +++ b/packages/web3js/src/index.ts @@ -0,0 +1,5 @@ +import { Web3jsSigner } from './lib/signer/web3js-signer'; +import { Web3jsContractFactory } from './lib/contract/web3js-contract-factory'; +import { Web3jsContractInterface } from './lib/contract/web3js-contract-interface'; + +export { Web3jsSigner, Web3jsContractFactory, Web3jsContractInterface }; diff --git a/packages/web3js/src/lib/contract/web3js-contract-factory.ts b/packages/web3js/src/lib/contract/web3js-contract-factory.ts new file mode 100644 index 0000000..e8b7267 --- /dev/null +++ b/packages/web3js/src/lib/contract/web3js-contract-factory.ts @@ -0,0 +1,22 @@ +import { Web3 } from 'web3'; +import { PayableCallOptions } from 'web3-types'; +import { Address, ContractFactory } from '@ditto-network/core'; +import { Web3jsContract } from './web3js-contract'; +import { Web3jsContractInterface } from './web3js-contract-interface'; + +export class Web3jsContractFactory + implements ContractFactory +{ + constructor( + private readonly web3: Web3, + private readonly txParamsDecorator: () => Promise = async () => ({}) + ) {} + + public getContract(address: Address, abi: string) { + return new Web3jsContract(address, abi, this.web3, this.txParamsDecorator); + } + + public getContractInterface(abi: string) { + return new Web3jsContractInterface(abi, this.web3); + } +} diff --git a/packages/web3js/src/lib/contract/web3js-contract-interface.ts b/packages/web3js/src/lib/contract/web3js-contract-interface.ts new file mode 100644 index 0000000..ffcf722 --- /dev/null +++ b/packages/web3js/src/lib/contract/web3js-contract-interface.ts @@ -0,0 +1,15 @@ +import { DittoContractInterface, Maybe } from '@ditto-network/core'; +import { Web3 } from 'web3'; +import { getMethodFromAbi } from '../utils/get-method-from-abi'; + +export class Web3jsContractInterface implements DittoContractInterface { + constructor(private readonly abi: string, private readonly web3: Web3) {} + + public encodeFunctionData(method: string, params: unknown[]): string { + return this.web3.eth.abi.encodeFunctionCall(getMethodFromAbi(method, this.abi), params); + } + + public selector(method: string): Maybe { + return this.web3.eth.abi.encodeFunctionSignature(getMethodFromAbi(method, this.abi)); + } +} diff --git a/packages/web3js/src/lib/contract/web3js-contract.ts b/packages/web3js/src/lib/contract/web3js-contract.ts new file mode 100644 index 0000000..cd8c18e --- /dev/null +++ b/packages/web3js/src/lib/contract/web3js-contract.ts @@ -0,0 +1,66 @@ +import { Address, DittoContract, Maybe } from '@ditto-network/core'; +import { Contract, Web3 } from 'web3'; +import { PayableCallOptions } from 'web3-types'; +import { Web3jsContractInterface } from './web3js-contract-interface'; +import { getMethodFromAbi } from '../utils/get-method-from-abi'; +import { webPromiEventToTxPromise } from '../utils/web-promi-event-to-tx-promise'; + +export class Web3jsContract implements DittoContract { + private readonly nativeContract: Contract; + private contractInterface: Web3jsContractInterface; + private readonly abi: Array>; + + constructor( + address: Address, + abi: string, + web3: Web3, + private readonly txParamsEnrichFn: () => Promise = async () => ({}) + ) { + this.abi = JSON.parse(abi); + + this.nativeContract = new Contract(JSON.parse(abi), address); + this.nativeContract.provider = web3.currentProvider; + + this.contractInterface = new Web3jsContractInterface(abi, web3); + } + + public async call(method: string, ...params: P): Promise { + if (this.isReadOnlyMethod(method)) { + const result = await this.nativeContract.methods[method](...params).call(); + return result as R; + } + + const txParams = await this.txParamsEnrichFn(); + const gas = await this.estimateGas(method, params, txParams); + + return webPromiEventToTxPromise( + this.nativeContract.methods[method](...params).send({ + gas: `${gas}`, + type: 2, + ...txParams, + }) + ) as Promise; + } + + public encodeFunctionData(method: string, params: unknown[]): string { + return this.contractInterface.encodeFunctionData(method, params); + } + + public async estimateGas( + method: string, + params: unknown[], + txParams?: PayableCallOptions + ): Promise { + txParams = txParams || (await this.txParamsEnrichFn()); + + return this.nativeContract.methods[method](...params).estimateGas(txParams); + } + + public selector(method: string): Maybe { + return this.contractInterface.selector(method); + } + + private isReadOnlyMethod(method: string): boolean { + return getMethodFromAbi(method, this.abi).stateMutability === 'view'; + } +} diff --git a/packages/web3js/src/lib/signer/web3js-signer.ts b/packages/web3js/src/lib/signer/web3js-signer.ts new file mode 100644 index 0000000..f7f558c --- /dev/null +++ b/packages/web3js/src/lib/signer/web3js-signer.ts @@ -0,0 +1,68 @@ +import { + Address, + DittoSigner, + MutationTransactionReturnType, + Transaction, +} from '@ditto-network/core'; +import { Web3 } from 'web3'; +import { webPromiEventToTxPromise } from '../utils/web-promi-event-to-tx-promise'; +import { PayableCallOptions } from 'web3-types'; + +export class Web3jsSigner implements DittoSigner { + constructor( + private readonly web3: Web3, + private readonly address: Address, + private readonly txParamsDecorator: () => Promise = async () => ({}) + ) {} + + public getAddress(): Promise
{ + return Promise.resolve(this.address); + } + + public async getBalance(address: Address): Promise { + const balance = await this.web3.eth.getBalance(address); + return balance.toString(); + } + + public async sendTransaction(tx: Transaction): Promise { + const txParams = await this.txParamsDecorator(); + + const enrichedTx = { + type: BigInt(2), + ...txParams, + ...tx, + }; + + return webPromiEventToTxPromise( + this.web3.eth.sendTransaction({ + ...enrichedTx, + gas: await this.web3.eth.estimateGas(enrichedTx), + }) + ); + } + + public async signMessage(message: string): Promise { + const address = await this.getAddress(); + + if (typeof window !== 'undefined' && (window as any).ethereum) { + const signedMessage = await (window as any).ethereum.request({ + method: 'personal_sign', + params: [message, address], + }); + + if (typeof signedMessage === 'string') { + return signedMessage; + } + + return signedMessage as string; + } + + const signedMessage = await this.web3.eth.sign(this.web3.utils.asciiToHex(message), address); + + if (typeof signedMessage === 'string') { + return signedMessage; + } + + return signedMessage.signature as string; + } +} diff --git a/packages/web3js/src/lib/utils/deferred-promise.ts b/packages/web3js/src/lib/utils/deferred-promise.ts new file mode 100644 index 0000000..9354d11 --- /dev/null +++ b/packages/web3js/src/lib/utils/deferred-promise.ts @@ -0,0 +1,16 @@ +export const createDeferredPromise = () => { + let resolve: (input: T) => void; + let reject: (reason?: Error) => void; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + return { promise, resolve, reject } as { + promise: Promise; + resolve: (input: T) => void; + reject: (reason?: Error) => void; + }; +}; diff --git a/packages/web3js/src/lib/utils/get-method-from-abi.ts b/packages/web3js/src/lib/utils/get-method-from-abi.ts new file mode 100644 index 0000000..d551eca --- /dev/null +++ b/packages/web3js/src/lib/utils/get-method-from-abi.ts @@ -0,0 +1,17 @@ +import { DittoContractMethodNotFoundError } from '@ditto-network/core'; +import { AbiFunctionFragment } from 'web3'; + +export const getMethodFromAbi = ( + methodName: string, + abi: string | Array> +): AbiFunctionFragment => { + const methodAbi = (Array.isArray(abi) ? abi : JSON.parse(abi)).find( + (item: any) => item.name === methodName && item.type === 'function' + ) as AbiFunctionFragment; + + if (!methodAbi) { + throw new DittoContractMethodNotFoundError(); + } + + return methodAbi; +}; diff --git a/packages/web3js/src/lib/utils/web-promi-event-to-tx-promise.ts b/packages/web3js/src/lib/utils/web-promi-event-to-tx-promise.ts new file mode 100644 index 0000000..4c53820 --- /dev/null +++ b/packages/web3js/src/lib/utils/web-promi-event-to-tx-promise.ts @@ -0,0 +1,30 @@ +import { Web3PromiEvent } from 'web3'; +import { createDeferredPromise } from './deferred-promise'; +import { MutationTransactionReturnType } from '@ditto-network/core'; + +export const webPromiEventToTxPromise = async ( + input: Web3PromiEvent +): Promise => { + const { + promise: deferredPromise, + resolve: deferredResolve, + reject: deferredReject, + } = createDeferredPromise(); + + return new Promise((resolve, reject) => { + input + .on('transactionHash', (hash) => { + resolve({ + hash, + wait: () => deferredPromise, + }); + }) + .on('error', (error) => { + reject(error); + deferredReject(error); + }) + .on('receipt', (receipt) => { + deferredResolve(receipt); + }); + }); +}; diff --git a/packages/web3js/tsconfig.json b/packages/web3js/tsconfig.json new file mode 100644 index 0000000..752bbf9 --- /dev/null +++ b/packages/web3js/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true, + "resolveJsonModule": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/web3js/tsconfig.lib.json b/packages/web3js/tsconfig.lib.json new file mode 100644 index 0000000..ce3b531 --- /dev/null +++ b/packages/web3js/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["vite.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/web3js/tsconfig.spec.json b/packages/web3js/tsconfig.spec.json new file mode 100644 index 0000000..0edf3f2 --- /dev/null +++ b/packages/web3js/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"] + }, + "include": [ + "vite.config.ts", + "vitest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/packages/web3js/vite.config.ts b/packages/web3js/vite.config.ts new file mode 100644 index 0000000..68b534f --- /dev/null +++ b/packages/web3js/vite.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite'; + +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +export default defineConfig({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/web3js', + + plugins: [nxViteTsPaths()], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + + test: { + globals: true, + cache: { dir: '../../node_modules/.vitest' }, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { reportsDirectory: '../../coverage/packages/web3js', provider: 'v8' }, + }, +}); diff --git a/tsconfig.base.json b/tsconfig.base.json index 3c1127d..bf621cf 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,7 +16,8 @@ "baseUrl": ".", "paths": { "@ditto-network/core": ["packages/core/src/index.ts"], - "@ditto-network/ethers": ["packages/ethers/src/index.ts"] + "@ditto-network/ethers": ["packages/ethers/src/index.ts"], + "@ditto-network/web3.js": ["packages/web3js/src/index.ts"] } }, "exclude": ["node_modules", "tmp"]