diff --git a/package.json b/package.json index fad6ee2bb..b268069f2 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "@ethersproject/bignumber": "^5.1.1", "@ethersproject/bytes": "^5.0.8", "async-mutex": "^0.4.0", - "ethers": "^5.1.0" + "ethers": "^5.1.0", + "viem": "^2.21.48" }, "devDependencies": { "@arbitrum/nitro-contracts": "^1.1.1", @@ -84,7 +85,7 @@ "ts-node": "^10.2.1", "tslint": "^6.1.3", "typechain": "7.0.0", - "typescript": "^4.9.5", + "typescript": "^5.6.3", "yargs": "^17.3.1" }, "files": [ diff --git a/scripts/testSetup.ts b/scripts/testSetup.ts index 10bc2c68b..6a827c8ff 100644 --- a/scripts/testSetup.ts +++ b/scripts/testSetup.ts @@ -40,6 +40,7 @@ import { isArbitrumNetworkWithCustomFeeToken, } from '../tests/integration/custom-fee-token/customFeeTokenTestHelpers' import { fundParentSigner } from '../tests/integration/testHelpers' +import { Chain } from 'viem' dotenv.config() @@ -85,6 +86,8 @@ export const testSetup = async (): Promise<{ inboxTools: InboxTools parentDeployer: Signer childDeployer: Signer + localEthChain: Chain + localArbChain: Chain }> => { const ethProvider = new JsonRpcProvider(config.ethUrl) const arbProvider = new JsonRpcProvider(config.arbUrl) @@ -113,6 +116,23 @@ export const testSetup = async (): Promise<{ assertArbitrumNetworkHasTokenBridge(setChildChain) + // Generate Viem chains using the network data we already have + const localEthChain = generateViemChain( + { + chainId: setChildChain.parentChainId, + name: 'EthLocal', + }, + config.ethUrl + ) + + const localArbChain = generateViemChain( + { + chainId: setChildChain.chainId, + name: setChildChain.name, + }, + config.arbUrl + ) + const erc20Bridger = new Erc20Bridger(setChildChain) const adminErc20Bridger = new AdminErc20Bridger(setChildChain) const ethBridger = new EthBridger(setChildChain) @@ -136,6 +156,8 @@ export const testSetup = async (): Promise<{ inboxTools, parentDeployer, childDeployer, + localEthChain, + localArbChain, } } @@ -153,3 +175,25 @@ export function getLocalNetworksFromFile(): { return { l2Network: localL2, l3Network: localL3 } } + +function generateViemChain( + networkData: { + chainId: number + name: string + }, + rpcUrl: string +): Chain { + return { + id: networkData.chainId, + name: networkData.name, + nativeCurrency: { + decimals: 18, + name: 'Ether', + symbol: 'ETH', + }, + rpcUrls: { + default: { http: [rpcUrl] }, + public: { http: [rpcUrl] }, + }, + } as const +} diff --git a/src/experimental/actions.ts b/src/experimental/actions.ts new file mode 100644 index 000000000..c4f6364cd --- /dev/null +++ b/src/experimental/actions.ts @@ -0,0 +1,221 @@ +import { BigNumber } from 'ethers' +import { + Account, + Address, + Hash, + PublicClient, + TransactionRequest, + WalletClient, +} from 'viem' +import { EthBridger } from '../lib/assetBridger/ethBridger' +import { + transformPublicClientToProvider, + viemTransactionReceiptToEthersTransactionReceipt, +} from './transformViemToEthers' +import { ParentTransactionReceipt } from '../lib/message/ParentTransaction' +import { ParentToChildMessageStatus } from '../lib/message/ParentToChildMessage' + +export type PrepareDepositEthParameters = { + amount: bigint + account: Account | Address +} + +const DEFAULT_CONFIRMATIONS = 1 +const DEFAULT_TIMEOUT = 1000 * 60 * 5 // 5 minutes + +export type WaitForCrossChainTxParameters = { + hash: Hash + timeout?: number + confirmations?: number +} + +export type SendCrossChainTransactionParameters = { + request: TransactionRequest + timeout?: number + confirmations?: number +} + +export type CrossChainTransactionStatus = { + status: 'success' | 'failed' + complete: boolean + message?: unknown + childTxReceipt?: unknown + hash: Hash +} + +export type DepositEthParameters = { + amount: bigint + account: Account | Address + confirmations?: number + timeout?: number +} + +export type ArbitrumDepositActions = { + prepareDepositEthTransaction: ( + params: PrepareDepositEthParameters + ) => Promise +} + +export type ArbitrumParentWalletActions = { + waitForCrossChainTransaction: ( + params: WaitForCrossChainTxParameters + ) => Promise + + sendCrossChainTransaction: ( + params: SendCrossChainTransactionParameters + ) => Promise + + depositEth: ( + params: DepositEthParameters + ) => Promise +} + +async function prepareDepositEthTransaction( + client: PublicClient, + { amount, account }: PrepareDepositEthParameters +): Promise { + const provider = transformPublicClientToProvider(client) + const ethBridger = await EthBridger.fromProvider(provider) + const request = await ethBridger.getDepositRequest({ + amount: BigNumber.from(amount), + from: typeof account === 'string' ? account : account.address, + }) + + return { + to: request.txRequest.to as `0x${string}`, + value: BigNumber.from(request.txRequest.value).toBigInt(), + data: request.txRequest.data as `0x${string}`, + } +} + +async function waitForCrossChainTransaction( + parentClient: PublicClient, + childClient: PublicClient, + { + hash, + confirmations = DEFAULT_CONFIRMATIONS, + timeout = DEFAULT_TIMEOUT, + }: WaitForCrossChainTxParameters +): Promise { + const childProvider = transformPublicClientToProvider(childClient) + + const viemReceipt = await parentClient.waitForTransactionReceipt({ + hash, + confirmations, + }) + + const ethersReceipt = + viemTransactionReceiptToEthersTransactionReceipt(viemReceipt) + const parentReceipt = new ParentTransactionReceipt(ethersReceipt) + + // Try to get eth deposits first + try { + const ethDeposits = await parentReceipt.getEthDeposits(childProvider) + if (ethDeposits.length > 0) { + const result = await ethDeposits[0].wait(confirmations, timeout) + return { + status: result ? 'success' : 'failed', + complete: Boolean(result), + message: ethDeposits[0], + childTxReceipt: result, + hash, + } + } + } catch (e) { + // Not an eth deposit, continue to check for other message types + } + + // Check for other cross chain messages + try { + const messages = await parentReceipt.getParentToChildMessages(childProvider) + if (messages.length > 0) { + const result = await messages[0].waitForStatus(confirmations, timeout) + return { + status: + result.status === ParentToChildMessageStatus.REDEEMED + ? 'success' + : 'failed', + complete: result.status === ParentToChildMessageStatus.REDEEMED, + message: messages[0], + childTxReceipt: result, + hash, + } + } + } catch (e) { + // Not a cross chain message + } + + throw new Error('No cross chain message found in transaction') +} + +async function sendCrossChainTransaction( + parentClient: PublicClient, + childClient: PublicClient, + walletClient: WalletClient, + { + request, + confirmations = DEFAULT_CONFIRMATIONS, + timeout = DEFAULT_TIMEOUT, + }: SendCrossChainTransactionParameters +): Promise { + const hash = await walletClient.sendTransaction({ + ...request, + chain: walletClient.chain, + account: walletClient.account as Account, + }) + + return waitForCrossChainTransaction(parentClient, childClient, { + hash, + confirmations, + timeout, + }) +} + +async function depositEth( + parentClient: PublicClient, + childClient: PublicClient, + walletClient: WalletClient, + { + amount, + account, + confirmations = DEFAULT_CONFIRMATIONS, + timeout = DEFAULT_TIMEOUT, + }: DepositEthParameters +): Promise { + const request = await prepareDepositEthTransaction(childClient, { + amount, + account, + }) + + return sendCrossChainTransaction(parentClient, childClient, walletClient, { + request, + confirmations, + timeout, + }) +} + +export function arbitrumParentClientActions() { + return (client: PublicClient): ArbitrumDepositActions => ({ + prepareDepositEthTransaction: params => + prepareDepositEthTransaction(client, params), + }) +} + +export function arbitrumParentWalletActions( + parentClient: PublicClient, + childClient: PublicClient +) { + return (walletClient: WalletClient): ArbitrumParentWalletActions => ({ + waitForCrossChainTransaction: (params: WaitForCrossChainTxParameters) => + waitForCrossChainTransaction(parentClient, childClient, params), + sendCrossChainTransaction: (params: SendCrossChainTransactionParameters) => + sendCrossChainTransaction( + parentClient, + childClient, + walletClient, + params + ), + depositEth: (params: DepositEthParameters) => + depositEth(parentClient, childClient, walletClient, params), + }) +} diff --git a/src/experimental/createArbitrumClient.ts b/src/experimental/createArbitrumClient.ts new file mode 100644 index 000000000..eb30876ed --- /dev/null +++ b/src/experimental/createArbitrumClient.ts @@ -0,0 +1,59 @@ +import { + Chain, + PublicClient, + WalletClient, + createPublicClient, + http, +} from 'viem' +import { + ArbitrumDepositActions, + ArbitrumParentWalletActions, + arbitrumParentClientActions, + arbitrumParentWalletActions, +} from './actions' + +export type ArbitrumClients = { + parentPublicClient: PublicClient + childPublicClient: PublicClient & ArbitrumDepositActions + parentWalletClient: WalletClient & ArbitrumParentWalletActions + childWalletClient?: WalletClient +} + +export type CreateArbitrumClientParams = { + parentChain: Chain + childChain: Chain + parentRpcUrl?: string + childRpcUrl?: string + parentWalletClient: WalletClient + childWalletClient?: WalletClient +} + +export function createArbitrumClient({ + parentChain, + childChain, + parentRpcUrl, + childRpcUrl, + parentWalletClient, + childWalletClient, +}: CreateArbitrumClientParams): ArbitrumClients { + const parentPublicClient = createPublicClient({ + chain: parentChain, + transport: http(parentRpcUrl || parentChain.rpcUrls.default.http[0]), + }) + + const childPublicClient = createPublicClient({ + chain: childChain, + transport: http(childRpcUrl || childChain.rpcUrls.default.http[0]), + }).extend(arbitrumParentClientActions()) + + const extendedParentWalletClient = parentWalletClient.extend( + arbitrumParentWalletActions(parentPublicClient, childPublicClient) + ) + + return { + parentPublicClient, + childPublicClient, + parentWalletClient: extendedParentWalletClient, + childWalletClient, + } +} diff --git a/src/experimental/transformViemToEthers.ts b/src/experimental/transformViemToEthers.ts new file mode 100644 index 000000000..9acee96d4 --- /dev/null +++ b/src/experimental/transformViemToEthers.ts @@ -0,0 +1,95 @@ +import { + Log as EthersLog, + TransactionReceipt as EthersTransactionReceipt, +} from '@ethersproject/abstract-provider' +import { StaticJsonRpcProvider } from '@ethersproject/providers' +import { BigNumber } from 'ethers' +import { + Chain, + Client, + PublicClient, + Transport, + Log as ViemLog, + TransactionReceipt as ViemTransactionReceipt, +} from 'viem' + +// based on https://wagmi.sh/react/ethers-adapters#reference-implementation +export function publicClientToProvider( + publicClient: PublicClient +) { + const { chain } = publicClient + + if (typeof chain === 'undefined') { + throw new Error(`[publicClientToProvider] "chain" is undefined`) + } + + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + + return new StaticJsonRpcProvider(chain.rpcUrls.default.http[0], network) +} + +function isPublicClient(object: any): object is PublicClient { + return ( + object !== undefined && + object !== null && + typeof object === 'object' && + 'transport' in object && + object.transport !== null && + typeof object.transport === 'object' && + 'url' in object.transport && + typeof object.transport.url === 'string' && + object.type === 'publicClient' + ) +} + +export const transformPublicClientToProvider = ( + provider: PublicClient | Client +): StaticJsonRpcProvider => { + if (isPublicClient(provider)) { + return publicClientToProvider(provider) + } + throw new Error('Invalid provider') +} + +function viemLogToEthersLog(log: ViemLog): EthersLog { + return { + blockNumber: Number(log.blockNumber), + blockHash: log.blockHash!, + transactionIndex: log.transactionIndex!, + removed: log.removed, + address: log.address, + data: log.data, + topics: log.topics, + transactionHash: log.transactionHash!, + logIndex: log.logIndex!, + } +} + +export function viemTransactionReceiptToEthersTransactionReceipt( + receipt: ViemTransactionReceipt +): EthersTransactionReceipt { + return { + to: receipt.to!, + from: receipt.from!, + contractAddress: receipt.contractAddress!, + transactionIndex: receipt.transactionIndex, + gasUsed: BigNumber.from(receipt.gasUsed), + logsBloom: receipt.logsBloom, + blockHash: receipt.blockHash, + transactionHash: receipt.transactionHash, + logs: receipt.logs.map(log => viemLogToEthersLog(log)), + blockNumber: Number(receipt.blockNumber), + // todo: if we need this we can add it later + confirmations: -1, + cumulativeGasUsed: BigNumber.from(receipt.cumulativeGasUsed), + effectiveGasPrice: BigNumber.from(receipt.effectiveGasPrice), + // all transactions that we care about are well past byzantium + byzantium: true, + type: Number(receipt.type), + status: receipt.status === 'success' ? 1 : 0, + } +} diff --git a/tests/integration/arbitrumDepositActions.test.ts b/tests/integration/arbitrumDepositActions.test.ts new file mode 100644 index 000000000..3ae4cb9b6 --- /dev/null +++ b/tests/integration/arbitrumDepositActions.test.ts @@ -0,0 +1,126 @@ +import { expect } from 'chai' +import { createWalletClient, http, parseEther, type Chain } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { config, testSetup } from '../../scripts/testSetup' +import { createArbitrumClient } from '../../src/experimental/createArbitrumClient' +import { fundParentSigner } from './testHelpers' +import { + approveParentCustomFeeToken, + fundParentCustomFeeToken, + isArbitrumNetworkWithCustomFeeToken, + getAmountInEnvironmentDecimals, + normalizeBalanceDiffByDecimals as normalizeBalanceDiffFByDecimals, + approveCustomFeeTokenWithViem, +} from './custom-fee-token/customFeeTokenTestHelpers' + +describe('arbitrumDepositActions', function () { + let localEthChain: Chain + let localArbChain: Chain + let setup: Awaited> + + before(async function () { + setup = await testSetup() + localEthChain = setup.localEthChain + localArbChain = setup.localArbChain + }) + + beforeEach(async function () { + const parentAccount = privateKeyToAccount(`0x${config.ethKey}`) + await fundParentSigner(setup.parentSigner) + if (isArbitrumNetworkWithCustomFeeToken()) { + await fundParentCustomFeeToken(parentAccount.address) + await approveParentCustomFeeToken(setup.parentSigner) + } + }) + + it('deposits ETH from parent to child using deposit action', async function () { + const parentAccount = privateKeyToAccount(`0x${config.ethKey}`) + const [depositAmount, tokenDecimals] = await getAmountInEnvironmentDecimals( + '0.01' + ) + + const baseParentWalletClient = createWalletClient({ + account: parentAccount, + chain: localEthChain, + transport: http(config.ethUrl), + }) + + const baseChildWalletClient = createWalletClient({ + account: parentAccount, + chain: localArbChain, + transport: http(config.arbUrl), + }) + + const { childPublicClient, parentWalletClient } = createArbitrumClient({ + parentChain: localEthChain, + childChain: localArbChain, + parentWalletClient: baseParentWalletClient, + childWalletClient: baseChildWalletClient, + }) + + const initialBalance = await childPublicClient.getBalance({ + address: parentAccount.address, + }) + + if (isArbitrumNetworkWithCustomFeeToken()) { + await approveCustomFeeTokenWithViem({ + parentAccount, + parentWalletClient, + chain: localEthChain, + }) + } + + const result = await parentWalletClient.depositEth({ + amount: depositAmount, + account: parentAccount, + }) + + expect(result.status).to.equal('success') + + const finalBalance = await childPublicClient.getBalance({ + address: parentAccount.address, + }) + + const balanceDiff = finalBalance - initialBalance + const normalizedBalanceDiff = normalizeBalanceDiffFByDecimals( + balanceDiff, + tokenDecimals + ) + + expect(normalizedBalanceDiff.toString()).to.equal(depositAmount.toString()) + }) + + it('handles deposit failure gracefully', async function () { + const parentAccount = privateKeyToAccount(`0x${config.ethKey}`) + const depositAmount = parseEther('999999999') + + const baseParentWalletClient = createWalletClient({ + account: parentAccount, + chain: localEthChain, + transport: http(config.ethUrl), + }) + + const baseChildWalletClient = createWalletClient({ + account: parentAccount, + chain: localArbChain, + transport: http(config.arbUrl), + }) + + const { parentWalletClient } = createArbitrumClient({ + parentChain: localEthChain, + childChain: localArbChain, + parentWalletClient: baseParentWalletClient, + childWalletClient: baseChildWalletClient, + }) + + try { + await parentWalletClient.depositEth({ + amount: depositAmount, + account: parentAccount, + }) + expect.fail('Should have thrown an error') + } catch (error) { + expect(error).to.exist + } + }) +}) diff --git a/tests/integration/custom-fee-token/customFeeTokenTestHelpers.ts b/tests/integration/custom-fee-token/customFeeTokenTestHelpers.ts index a6e04a79d..a4cc493cd 100644 --- a/tests/integration/custom-fee-token/customFeeTokenTestHelpers.ts +++ b/tests/integration/custom-fee-token/customFeeTokenTestHelpers.ts @@ -1,5 +1,14 @@ import { StaticJsonRpcProvider } from '@ethersproject/providers' import { Signer, Wallet, ethers, utils } from 'ethers' +import { + Account, + parseEther, + parseUnits, + type Hex, + type WalletClient, + type Chain, + formatUnits, +} from 'viem' import { testSetup as _testSetup, @@ -58,7 +67,7 @@ export async function fundParentCustomFeeToken( const tx = await tokenContract.transfer( address, - utils.parseUnits('10', decimals) + utils.parseUnits('1000', decimals) ) await tx.wait() } @@ -109,3 +118,63 @@ export async function fundChildCustomFeeToken(childSigner: Signer) { }) await tx.wait() } + +export async function getAmountInEnvironmentDecimals( + amount: string +): Promise<[bigint, number]> { + if (isArbitrumNetworkWithCustomFeeToken()) { + const tokenDecimals = await getNativeTokenDecimals({ + parentProvider: ethProvider(), + childNetwork: localNetworks().l3Network!, + }) + return [parseUnits(amount, tokenDecimals), tokenDecimals] + } + return [parseEther(amount), 18] // ETH decimals +} + +export function normalizeBalanceDiffByDecimals( + balanceDiff: bigint, + tokenDecimals: number +): bigint { + // Convert to 18 decimals (ETH standard) for comparison + if (tokenDecimals === 18) return balanceDiff + + // Convert to decimal string with proper precision + const formattedDiff = formatUnits(balanceDiff, 18) + // Parse back with target decimals + return parseUnits(formattedDiff, tokenDecimals) +} + +export async function approveCustomFeeTokenWithViem({ + parentAccount, + parentWalletClient, + chain, +}: { + parentAccount: { address: string } + parentWalletClient: WalletClient + chain: Chain +}) { + if (!isArbitrumNetworkWithCustomFeeToken()) return + + const networks = localNetworks() + const inbox = networks.l3Network!.ethBridge.inbox + + const currentAllowance = await getParentCustomFeeTokenAllowance( + parentAccount.address, + inbox + ) + + // Only approve if allowance is insufficient + if (currentAllowance.lt(ethers.constants.MaxUint256)) { + const ethBridger = await EthBridger.fromProvider(arbProvider()) + const approveRequest = ethBridger.getApproveGasTokenRequest() + await parentWalletClient.sendTransaction({ + to: approveRequest.to as Hex, + data: approveRequest.data as Hex, + account: parentAccount as Account, + chain, + value: BigInt(0), + kzg: undefined, + }) + } +} diff --git a/tsconfig.json b/tsconfig.json index 3a5901b62..0cff0f779 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2017", + "target": "ES2020", "module": "commonjs", "declaration": true, "rootDir": "./src", @@ -14,7 +14,8 @@ "noImplicitThis": true, "resolveJsonModule": true, "esModuleInterop": true, - "experimentalDecorators": true + "experimentalDecorators": true, + "skipLibCheck": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.js"] } diff --git a/yarn.lock b/yarn.lock index 07788bae1..21d707f73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@^1.10.1": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" + integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== + "@aduh95/viz.js@^3.7.0": version "3.7.0" resolved "https://registry.yarnpkg.com/@aduh95/viz.js/-/viz.js-3.7.0.tgz#a20d86c5fc8f6abebdc39b96a4326e10375d77c0" @@ -1086,11 +1091,23 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@noble/curves@1.6.0", "@noble/curves@^1.4.0", "@noble/curves@^1.6.0", "@noble/curves@~1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.6.0.tgz#be5296ebcd5a1730fccea4786d420f87abfeb40b" + integrity sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ== + dependencies: + "@noble/hashes" "1.5.0" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.5.0", "@noble/hashes@^1.4.0", "@noble/hashes@^1.5.0", "@noble/hashes@~1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -1393,6 +1410,11 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.3.tgz#8584115565228290a6c6c4961973e0903bb3df2f" integrity sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q== +"@scure/base@~1.1.7", "@scure/base@~1.1.8": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== + "@scure/bip32@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" @@ -1402,6 +1424,15 @@ "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.0" +"@scure/bip32@1.5.0", "@scure/bip32@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.5.0.tgz#dd4a2e1b8a9da60e012e776d954c4186db6328e6" + integrity sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw== + dependencies: + "@noble/curves" "~1.6.0" + "@noble/hashes" "~1.5.0" + "@scure/base" "~1.1.7" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -1410,6 +1441,14 @@ "@noble/hashes" "~1.2.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.4.0", "@scure/bip39@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.4.0.tgz#664d4f851564e2e1d4bffa0339f9546ea55960a6" + integrity sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw== + dependencies: + "@noble/hashes" "~1.5.0" + "@scure/base" "~1.1.8" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" @@ -1766,6 +1805,11 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abitype@1.0.6, abitype@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.6.tgz#76410903e1d88e34f1362746e2d407513c38565b" + integrity sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A== + abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" @@ -3212,6 +3256,11 @@ event-stream@4.0.1: stream-combiner "^0.2.2" through "^2.3.8" +eventemitter3@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -4083,6 +4132,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isows@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" + integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" @@ -4775,6 +4829,19 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +ox@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.1.2.tgz#0f791be2ccabeaf4928e6d423498fe1c8094e560" + integrity sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww== + dependencies: + "@adraffy/ens-normalize" "^1.10.1" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" + "@scure/bip32" "^1.5.0" + "@scure/bip39" "^1.4.0" + abitype "^1.0.6" + eventemitter3 "5.0.1" + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -5911,10 +5978,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.9.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== typical@^4.0.0: version "4.0.0" @@ -6006,6 +6073,29 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +viem@^2.21.48: + version "2.21.48" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.21.48.tgz#f8f1d0bf5381282e22e6a1f8b72ebd6e64426480" + integrity sha512-/hBHyG1gdIIuiQv0z9YmzXl5eWJa0UCZGwkeuQzH2Bmg6FIEwZeEcxgiytXZydip+p2wMBFa1jdr7o5O1+mrIg== + dependencies: + "@noble/curves" "1.6.0" + "@noble/hashes" "1.5.0" + "@scure/bip32" "1.5.0" + "@scure/bip39" "1.4.0" + abitype "1.0.6" + isows "1.0.6" + ox "0.1.2" + webauthn-p256 "0.0.10" + ws "8.18.0" + +webauthn-p256@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/webauthn-p256/-/webauthn-p256-0.0.10.tgz#877e75abe8348d3e14485932968edf3325fd2fdd" + integrity sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA== + dependencies: + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -6121,6 +6211,11 @@ ws@7.4.6, ws@7.5.10, ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== +ws@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + ws@8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"