diff --git a/.changeset/new-ears-study.md b/.changeset/new-ears-study.md new file mode 100644 index 000000000..4c67e9915 --- /dev/null +++ b/.changeset/new-ears-study.md @@ -0,0 +1,5 @@ +--- +"@rabbitholegg/questdk-plugin-stargate": minor +--- + +Add support for bridging on Arbitrum diff --git a/packages/registry/package.json b/packages/registry/package.json index 2a828ec25..066029bf1 100644 --- a/packages/registry/package.json +++ b/packages/registry/package.json @@ -47,6 +47,7 @@ "@rabbitholegg/questdk": "1.0.1-alpha.8", "@rabbitholegg/questdk-plugin-connext": "workspace:*", "@rabbitholegg/questdk-plugin-uniswap": "workspace:*", + "@rabbitholegg/questdk-plugin-stargate": "workspace:*", "@rabbitholegg/questdk-plugin-across": "workspace:*", "@rabbitholegg/questdk-plugin-polygon": "workspace:*", "@rabbitholegg/questdk-plugin-hop": "workspace:*", diff --git a/packages/registry/src/index.ts b/packages/registry/src/index.ts index 3be14204c..6baab2e40 100644 --- a/packages/registry/src/index.ts +++ b/packages/registry/src/index.ts @@ -11,6 +11,7 @@ import { import { Connext } from '@rabbitholegg/questdk-plugin-connext' import { Uniswap } from '@rabbitholegg/questdk-plugin-uniswap' +import { Stargate } from '@rabbitholegg/questdk-plugin-stargate' import { Across } from '@rabbitholegg/questdk-plugin-across' import { Polygon } from '@rabbitholegg/questdk-plugin-polygon' import { Optimism } from '@rabbitholegg/questdk-plugin-optimism' @@ -20,11 +21,12 @@ import { Arbitrum } from '@rabbitholegg/questdk-plugin-arbitrum' export const plugins: Record = { [Connext.pluginId]: Connext, [Uniswap.pluginId]: Uniswap, - [Across.pluginId]: Across, + [Stargate.pluginId]: Stargate, [Polygon.pluginId]: Polygon, - [Optimism.pluginId]: Optimism, [Hop.pluginId]: Hop, [Arbitrum.pluginId]: Arbitrum, + [Across.pluginId]: Across, + [Optimism.pluginId]: Optimism, } export const getPlugin = (pluginId: string) => { diff --git a/packages/stargate/CHANGELOG.md b/packages/stargate/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/stargate/README.md b/packages/stargate/README.md new file mode 100644 index 000000000..c69114b6d --- /dev/null +++ b/packages/stargate/README.md @@ -0,0 +1,25 @@ + +## ETH/BASE TOKEN +Other than the token address retrieval this is a pretty trivial to implement plugin. +Unfortunatly in order to get the token address we need to do some direct chain reads but nothing too heavy. + + +### Deposit ETH +Deposit to Arbitrum Layer Zero +https://etherscan.io/tx/0xe3a54ddf9a09ee9df6abe87af38cc418c516fb198fc635972615418f5254812a + +### Withdraw ETH +Withdraw ETH to Optimism +https://arbiscan.io/tx/0xc6fa0deba78d6228d3cb343a908390162955dcb3d6d5a8e952ef24c54f7c453f + +## ERC20 + +### Deposit ERC20 +https://etherscan.io/tx/0x28901f729bd89400b5c046eb73abf0656ab82cb02463e47562d7ce24737d263f +### Withdraw ERC20 +USDT +https://arbiscan.io/tx/0xb983d41651ccad84a70600564376975a3a3385dae53de35259486f20dd2d8d4d + + +You can use the following example code to pull down test transactions in the correct format easily: +https://viem.sh/docs/actions/public/getTransaction.html#example \ No newline at end of file diff --git a/packages/stargate/package.json b/packages/stargate/package.json new file mode 100644 index 000000000..a99cab5b0 --- /dev/null +++ b/packages/stargate/package.json @@ -0,0 +1,51 @@ +{ + "name": "@rabbitholegg/questdk-plugin-stargate", + "private": true, + "version": "1.0.0-alpha.3", + "type": "module", + "exports": { + "require": "./dist/cjs/index.js", + "import": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts" + }, + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "packageManager": "pnpm@8.3.1", + "description": "", + "scripts": { + "bench": "vitest bench", + "bench:ci": "CI=true vitest bench", + "build": "pnpm run clean && pnpm run build:cjs && pnpm run build:esm && pnpm run build:types", + "build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", + "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir ./dist/esm && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}'", + "build:types": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", + "clean": "rimraf dist", + "format": "rome format . --write", + "lint": "rome check .", + "lint:fix": "pnpm lint --apply", + "preinstall": "npx only-allow pnpm", + "test": "vitest dev", + "test:cov": "vitest dev --coverage", + "test:ci": "CI=true vitest --coverage", + "test:ui": "vitest dev --ui" + }, + "keywords": [], + "author": "", + "license": "ISC", + "types": "./dist/types/index.d.ts", + "typings": "./dist/types/index.d.ts", + "devDependencies": { + "@types/node": "20.4.5", + "@vitest/coverage-v8": "0.33.0", + "rimraf": "5.0.1", + "rome": "12.1.3", + "ts-node": "10.9.1", + "tsconfig": "workspace:*", + "typescript": "5.1.6", + "vitest": "0.33.0" + }, + "dependencies": { + "@rabbitholegg/questdk": "1.0.1-alpha.9", + "viem": "1.6.7" + } +} diff --git a/packages/stargate/src/Stargate.test.ts b/packages/stargate/src/Stargate.test.ts new file mode 100644 index 000000000..e47569cbe --- /dev/null +++ b/packages/stargate/src/Stargate.test.ts @@ -0,0 +1,162 @@ +import { GreaterThanOrEqual, apply } from '@rabbitholegg/questdk/filter' +import { describe, expect, test } from 'vitest' +import { bridge } from './Stargate.js' +import { + DEPOSIT_ETH, + DEPOSIT_ERC20, + WITHDRAW_ETH, + WITHDRAW_ERC20, +} from './test-transactions.js' +import { + ARBITRUM_LAYER_ZERO_CHAIN_ID, + POLYGON_LAYER_ZERO_CHAIN_ID, + ETH_LAYER_ZERO_CHAIN_ID, + OPTIMISM_LAYER_ZERO_CHAIN_ID, + LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID, +} from './chain-ids.js' +import { STARGATE_BRIDGE_ABI } from './abi.js' +import { parseEther } from 'viem' +import { + CHAIN_AND_POOL_TO_TOKEN_ADDRESS, + CHAIN_ID_TO_ROUTER_ADDRESS, + CHAIN_ID_TO_ETH_ROUTER_ADDRESS, +} from './contract-addresses.js' + +const ARBITRUM_USDC_ADDRESS = '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8' +const ARBITRUM_USDT_ADDRESS = '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9' +const ARBITRUM_SGETH_ADDRESS = '0x82cbecf39bee528b5476fe6d1550af59a9db6fc0' + +const ETHEREUM_USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' +const ETHEREUM_SGETH_ADDRESS = '0x72E2F4830b9E45d52F80aC08CB2bEC0FeF72eD9c' + +const TEST_USER = '0x7c3bd1a09d7d86920451def20ae503322c8d0412' + +describe('Given the Across plugin', () => { + describe('When generating the filter', () => { + test('should return a valid bridge action filter for L2 token tx', async () => { + const filter = await bridge({ + sourceChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + destinationChainId: ETH_LAYER_ZERO_CHAIN_ID, + tokenAddress: ARBITRUM_USDC_ADDRESS, + amount: GreaterThanOrEqual(100000n), + recipient: TEST_USER, + }) + const sourcePool = + CHAIN_AND_POOL_TO_TOKEN_ADDRESS[ARBITRUM_LAYER_ZERO_CHAIN_ID][ + ARBITRUM_USDC_ADDRESS + ] + + expect(filter).to.deep.equal({ + chainId: LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID[ARBITRUM_LAYER_ZERO_CHAIN_ID], + to: CHAIN_ID_TO_ROUTER_ADDRESS[ARBITRUM_LAYER_ZERO_CHAIN_ID], + input: { + $abi: STARGATE_BRIDGE_ABI, + _srcPoolId: sourcePool, + _amountLD: { + $gte: '100000', + }, + _to: TEST_USER, + _dstChainId: ETH_LAYER_ZERO_CHAIN_ID, + }, + }) + }) + + test('should return a valid bridge action filter for L1 token tx', async () => { + const filter = await bridge({ + sourceChainId: ETH_LAYER_ZERO_CHAIN_ID, + destinationChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + tokenAddress: ETHEREUM_USDC_ADDRESS, + amount: GreaterThanOrEqual(100000n), + recipient: TEST_USER, + }) + const sourcePool = + CHAIN_AND_POOL_TO_TOKEN_ADDRESS[ETH_LAYER_ZERO_CHAIN_ID][ + ETHEREUM_USDC_ADDRESS + ] + + expect(filter).to.deep.equal({ + chainId: LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID[ETH_LAYER_ZERO_CHAIN_ID], + to: CHAIN_ID_TO_ROUTER_ADDRESS[ETH_LAYER_ZERO_CHAIN_ID], + input: { + $abi: STARGATE_BRIDGE_ABI, + _srcPoolId: sourcePool, + _amountLD: { + $gte: '100000', + }, + _to: TEST_USER, + _dstChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + }, + }) + }) + + test('should return a valid bridge action filter for L1 ETH tx', async () => { + const filter = await bridge({ + sourceChainId: ETH_LAYER_ZERO_CHAIN_ID, + destinationChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + tokenAddress: ETHEREUM_SGETH_ADDRESS, + amount: GreaterThanOrEqual(100000n), + recipient: TEST_USER, + }) + expect(filter).to.deep.equal({ + chainId: LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID[ETH_LAYER_ZERO_CHAIN_ID], + to: CHAIN_ID_TO_ETH_ROUTER_ADDRESS[ETH_LAYER_ZERO_CHAIN_ID], + input: { + $abi: STARGATE_BRIDGE_ABI, + _amountLD: { + $gte: '100000', + }, + _toAddress: TEST_USER, + _dstChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + }, + }) + }) + }) + describe('When applying the filter', () => { + test('should pass filter with valid L1 ETH tx', async () => { + const transaction = DEPOSIT_ETH + const filter = await bridge({ + sourceChainId: ETH_LAYER_ZERO_CHAIN_ID, + destinationChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + tokenAddress: ETHEREUM_SGETH_ADDRESS, + amount: GreaterThanOrEqual(parseEther('.04')), + recipient: '0x7c3bd1a09d7d86920451def20ae503322c8d0412', + }) + expect(apply(transaction, filter)).to.be.true + }) + test('should pass filter with valid L2 ETH tx', async () => { + const transaction = WITHDRAW_ETH + const filter = await bridge({ + sourceChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + destinationChainId: OPTIMISM_LAYER_ZERO_CHAIN_ID, + tokenAddress: ARBITRUM_SGETH_ADDRESS, + amount: GreaterThanOrEqual(parseEther('.6')), + recipient: '0x08bfa4ef61a457792c45240829529b43b019d941', + }) + expect(apply(transaction, filter)).to.be.true + }) + test('should pass filter with valid L1 Token tx', async () => { + const transaction = DEPOSIT_ERC20 + const filter = await bridge({ + sourceChainId: ETH_LAYER_ZERO_CHAIN_ID, + destinationChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + tokenAddress: ETHEREUM_USDC_ADDRESS, + amount: GreaterThanOrEqual('48500000'), // $250 USDC, + recipient: '0x0318ccfbfae5e2c06b2f533a35acecea13b9909f', + }) + expect(apply(transaction, filter)).to.be.true + }) + test('should pass filter with valid L2 token tx', async () => { + const transaction = WITHDRAW_ERC20 + const filter = await bridge({ + sourceChainId: ARBITRUM_LAYER_ZERO_CHAIN_ID, + destinationChainId: POLYGON_LAYER_ZERO_CHAIN_ID, + tokenAddress: ARBITRUM_USDT_ADDRESS, + amount: GreaterThanOrEqual('1200000000'), + recipient: '0x5ee8496532d3dcb8bc726d66d8cb4c45d979e71d', + }) + expect(apply(transaction, filter)).to.be.true + }) + }) + + test('should not pass filter with invalid transactions', () => {}) +}) diff --git a/packages/stargate/src/Stargate.ts b/packages/stargate/src/Stargate.ts new file mode 100644 index 000000000..9d834d319 --- /dev/null +++ b/packages/stargate/src/Stargate.ts @@ -0,0 +1,67 @@ +import { type BridgeActionParams, compressJson } from '@rabbitholegg/questdk' +import { type Address } from 'viem' +import { STARGATE_BRIDGE_ABI } from './abi.js' +import { + CHAIN_ID_ARRAY, + LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID, +} from './chain-ids.js' +import { + CHAIN_AND_POOL_TO_TOKEN_ADDRESS, + CHAIN_ID_TO_ROUTER_ADDRESS, + CHAIN_ID_TO_ETH_ROUTER_ADDRESS, +} from './contract-addresses.js' + +export const bridge = async (bridge: BridgeActionParams) => { + // This is the information we'll use to compose the Transaction object + const { + sourceChainId, + destinationChainId, + contractAddress, + tokenAddress, + amount, + recipient, + } = bridge + const layerOneChainId = LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID[sourceChainId] + const sourcePool = tokenAddress + ? CHAIN_AND_POOL_TO_TOKEN_ADDRESS[sourceChainId][tokenAddress] + : 0 + + if (sourcePool === 13) { + const targetContractAddress = CHAIN_ID_TO_ETH_ROUTER_ADDRESS[sourceChainId] + return compressJson({ + chainId: layerOneChainId, // The chainId of the source chain + to: contractAddress || targetContractAddress, // The contract address of the bridge + input: { + $abi: STARGATE_BRIDGE_ABI, // The ABI of the bridge contract + _amountLD: amount, // The amount of tokens to send + _toAddress: recipient, // The recipient of the tokens + _dstChainId: destinationChainId, // The chainId of the destination chain + }, // The input object is where we'll put the ABI and the parameters + }) + } + const targetContractAddress = CHAIN_ID_TO_ROUTER_ADDRESS[sourceChainId] + + // We always want to return a compressed JSON object which we'll transform into a TransactionFilter + return compressJson({ + chainId: layerOneChainId, // The chainId of the source chain + to: contractAddress || targetContractAddress, // The contract address of the bridge + input: { + $abi: STARGATE_BRIDGE_ABI, // The ABI of the bridge contract + _srcPoolId: sourcePool, // The source poolId + _amountLD: amount, // The amount of tokens to send + _to: recipient, // The recipient of the tokens + _dstChainId: destinationChainId, // The chainId of the destination chain + }, // The input object is where we'll put the ABI and the parameters + }) +} + +export const getSupportedTokenAddresses = async ( + _chainId: number, +): Promise => { + // Given a specific chain we would expect this function to return a list of supported token addresses + return [] +} + +export const getSupportedChainIds = async () => { + return CHAIN_ID_ARRAY as number[] +} diff --git a/packages/stargate/src/abi.ts b/packages/stargate/src/abi.ts new file mode 100644 index 000000000..f2b1cfdd3 --- /dev/null +++ b/packages/stargate/src/abi.ts @@ -0,0 +1,49 @@ +export const STARGATE_BRIDGE_ABI = [ + { + inputs: [ + { internalType: 'uint16', name: '_dstChainId', type: 'uint16' }, + { + internalType: 'address payable', + name: '_refundAddress', + type: 'address', + }, + { internalType: 'bytes', name: '_toAddress', type: 'bytes' }, + { internalType: 'uint256', name: '_amountLD', type: 'uint256' }, + { internalType: 'uint256', name: '_minAmountLD', type: 'uint256' }, + ], + name: 'swapETH', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint16', name: '_dstChainId', type: 'uint16' }, + { internalType: 'uint256', name: '_srcPoolId', type: 'uint256' }, + { internalType: 'uint256', name: '_dstPoolId', type: 'uint256' }, + { + internalType: 'address payable', + name: '_refundAddress', + type: 'address', + }, + { internalType: 'uint256', name: '_amountLD', type: 'uint256' }, + { internalType: 'uint256', name: '_minAmountLD', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'dstGasForCall', type: 'uint256' }, + { internalType: 'uint256', name: 'dstNativeAmount', type: 'uint256' }, + { internalType: 'bytes', name: 'dstNativeAddr', type: 'bytes' }, + ], + internalType: 'struct IStargateRouter.lzTxObj', + name: '_lzTxParams', + type: 'tuple', + }, + { internalType: 'bytes', name: '_to', type: 'bytes' }, + { internalType: 'bytes', name: '_payload', type: 'bytes' }, + ], + name: 'swap', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, +] as const diff --git a/packages/stargate/src/chain-ids.ts b/packages/stargate/src/chain-ids.ts new file mode 100644 index 000000000..87a12c369 --- /dev/null +++ b/packages/stargate/src/chain-ids.ts @@ -0,0 +1,51 @@ +export const ETH_LAYER_ZERO_CHAIN_ID: number = 101 +export const BNB_LAYER_ZERO_CHAIN_ID: number = 102 +export const AVALANCHE_LAYER_ZERO_CHAIN_ID: number = 106 +export const POLYGON_LAYER_ZERO_CHAIN_ID: number = 109 +export const ARBITRUM_LAYER_ZERO_CHAIN_ID: number = 110 +export const OPTIMISM_LAYER_ZERO_CHAIN_ID: number = 111 +export const FANTOM_LAYER_ZERO_CHAIN_ID: number = 112 +export const METIS_LAYER_ZERO_CHAIN_ID: number = 151 +export const KAVA_LAYER_ZERO_CHAIN_ID: number = 177 +export const LINEA_LAYER_ZERO_CHAIN_ID: number = 183 +export const BASE_LAYER_ZERO_CHAIN_ID: number = 184 + +export const ETH_CHAIN_ID: number = 1 +export const BNB_CHAIN_ID: number = 56 +export const AVALANCHE_CHAIN_ID: number = 43114 +export const POLYGON_CHAIN_ID: number = 137 +export const ARBITRUM_CHAIN_ID: number = 42161 +export const OPTIMISM_CHAIN_ID: number = 10 +export const FANTOM_CHAIN_ID: number = 250 +export const METIS_CHAIN_ID: number = 1088 +export const KAVA_CHAIN_ID: number = 2222 +export const LINEA_CHAIN_ID: number = 59144 +export const BASE_CHAIN_ID: number = 8453 + +export const LAYER_ZERO_TO_LAYER_ONE_CHAIN_ID: Record = { + [ETH_LAYER_ZERO_CHAIN_ID]: ETH_CHAIN_ID, + [BNB_LAYER_ZERO_CHAIN_ID]: BNB_CHAIN_ID, + [AVALANCHE_LAYER_ZERO_CHAIN_ID]: AVALANCHE_CHAIN_ID, + [POLYGON_LAYER_ZERO_CHAIN_ID]: POLYGON_CHAIN_ID, + [ARBITRUM_LAYER_ZERO_CHAIN_ID]: ARBITRUM_CHAIN_ID, + [OPTIMISM_LAYER_ZERO_CHAIN_ID]: OPTIMISM_CHAIN_ID, + [FANTOM_LAYER_ZERO_CHAIN_ID]: FANTOM_CHAIN_ID, + [METIS_LAYER_ZERO_CHAIN_ID]: METIS_CHAIN_ID, + [KAVA_LAYER_ZERO_CHAIN_ID]: KAVA_CHAIN_ID, + [LINEA_LAYER_ZERO_CHAIN_ID]: LINEA_CHAIN_ID, + [BASE_LAYER_ZERO_CHAIN_ID]: BASE_CHAIN_ID, +} as const + +export const CHAIN_ID_ARRAY = [ + ETH_LAYER_ZERO_CHAIN_ID, + BNB_LAYER_ZERO_CHAIN_ID, + AVALANCHE_LAYER_ZERO_CHAIN_ID, + POLYGON_LAYER_ZERO_CHAIN_ID, + ARBITRUM_LAYER_ZERO_CHAIN_ID, + OPTIMISM_LAYER_ZERO_CHAIN_ID, + FANTOM_LAYER_ZERO_CHAIN_ID, + METIS_LAYER_ZERO_CHAIN_ID, + KAVA_LAYER_ZERO_CHAIN_ID, + LINEA_LAYER_ZERO_CHAIN_ID, + BASE_LAYER_ZERO_CHAIN_ID, +] diff --git a/packages/stargate/src/contract-addresses.ts b/packages/stargate/src/contract-addresses.ts new file mode 100644 index 000000000..cac1b96e1 --- /dev/null +++ b/packages/stargate/src/contract-addresses.ts @@ -0,0 +1,176 @@ +import { + ETH_LAYER_ZERO_CHAIN_ID, + BNB_LAYER_ZERO_CHAIN_ID, + AVALANCHE_LAYER_ZERO_CHAIN_ID, + POLYGON_LAYER_ZERO_CHAIN_ID, + ARBITRUM_LAYER_ZERO_CHAIN_ID, + OPTIMISM_LAYER_ZERO_CHAIN_ID, + FANTOM_LAYER_ZERO_CHAIN_ID, + METIS_LAYER_ZERO_CHAIN_ID, + KAVA_LAYER_ZERO_CHAIN_ID, + LINEA_LAYER_ZERO_CHAIN_ID, + BASE_LAYER_ZERO_CHAIN_ID, +} from './chain-ids.js' + +export const ETHEREUM_ETH_ROUTER = '0x150f94B44927F078737562f0fcF3C95c01Cc2376' +export const ETHEREUM_ROUTER = '0x8731d54E9D02c286767d56ac03e8037C07e01e98' +export const BNB_ROUTER = '0x4a364f8c717cAAD9A442737Eb7b8A55cc6cf18D8' +export const AVALANCHE_ROUTER = '0x45A01E4e04F14f7A4a6702c74187c5F6222033cd' +export const POLYGON_ROUTER = '0x45A01E4e04F14f7A4a6702c74187c5F6222033cd' +export const ARBITRUM_ETH_ROUTER = '0xbf22f0f184bCcbeA268dF387a49fF5238dD23E40' +export const ARBITRUM_ROUTER = '0x53Bf833A5d6c4ddA888F69c22C88C9f356a41614' +export const OPTIMISM_ETH_ROUTER = '0xB49c4e680174E331CB0A7fF3Ab58afC9738d5F8b' +export const OPTIMISM_ROUTER = '0xB0D502E938ed5f4df2E681fE6E419ff29631d62b' +export const FANTOM_ROUTER = '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6' +export const METIS_ROUTER = '0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590' +export const BASE_ETH_ROUTER = '0x50B6EbC2103BFEc165949CC946d739d5650d7ae4' +export const BASE_ROUTER = '0x45f1A95A4D3f3836523F5c83673c797f4d4d263B' +export const LINEA_ETH_ROUTER = '0x8731d54E9D02c286767d56ac03e8037C07e01e98' +export const LINEA_ROUTER = '0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590' +export const KAVA_ROUTER = '0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590' + +// For some chains the ETH router is different than the router; in cases where it's not we populate with the router address +export const CHAIN_ID_TO_ETH_ROUTER_ADDRESS = { + [ETH_LAYER_ZERO_CHAIN_ID]: ETHEREUM_ETH_ROUTER, + [BNB_LAYER_ZERO_CHAIN_ID]: BNB_ROUTER, + [AVALANCHE_LAYER_ZERO_CHAIN_ID]: AVALANCHE_ROUTER, + [POLYGON_LAYER_ZERO_CHAIN_ID]: POLYGON_ROUTER, + [ARBITRUM_LAYER_ZERO_CHAIN_ID]: ARBITRUM_ETH_ROUTER, + [OPTIMISM_LAYER_ZERO_CHAIN_ID]: OPTIMISM_ETH_ROUTER, + [FANTOM_LAYER_ZERO_CHAIN_ID]: FANTOM_ROUTER, + [METIS_LAYER_ZERO_CHAIN_ID]: METIS_ROUTER, + [KAVA_LAYER_ZERO_CHAIN_ID]: KAVA_ROUTER, + [LINEA_LAYER_ZERO_CHAIN_ID]: LINEA_ETH_ROUTER, + [BASE_LAYER_ZERO_CHAIN_ID]: BASE_ETH_ROUTER, +} as const + +export const CHAIN_ID_TO_ROUTER_ADDRESS = { + [ETH_LAYER_ZERO_CHAIN_ID]: ETHEREUM_ROUTER, + [BNB_LAYER_ZERO_CHAIN_ID]: BNB_ROUTER, + [AVALANCHE_LAYER_ZERO_CHAIN_ID]: AVALANCHE_ROUTER, + [POLYGON_LAYER_ZERO_CHAIN_ID]: POLYGON_ROUTER, + [ARBITRUM_LAYER_ZERO_CHAIN_ID]: ARBITRUM_ROUTER, + [OPTIMISM_LAYER_ZERO_CHAIN_ID]: OPTIMISM_ROUTER, + [FANTOM_LAYER_ZERO_CHAIN_ID]: FANTOM_ROUTER, + [METIS_LAYER_ZERO_CHAIN_ID]: METIS_ROUTER, + [KAVA_LAYER_ZERO_CHAIN_ID]: KAVA_ROUTER, + [LINEA_LAYER_ZERO_CHAIN_ID]: LINEA_ROUTER, + [BASE_LAYER_ZERO_CHAIN_ID]: BASE_ROUTER, +} as const +export const USDC_POOL_ID: number = 1 +export const USDT_POOL_ID: number = 2 +export const ETH_POOL_ID: number = 13 + +// A lot of these key values are incorrect +export const CHAIN_AND_POOL_TO_TOKEN_ADDRESS_UNUSED: { + [chainId: number]: { [address: string]: number } +} = { + [ETH_LAYER_ZERO_CHAIN_ID]: { + '0xdf0770dF86a8034b3EFEf0A1Bb3c889B8332FF56': 1, + '0x38ea452219524bb87e18de1c24d3bb59510bd783': 2, + '0x0Faf1d2d3CED330824de3B8200fc8dc6E397850d': 3, + '0xfA0F307783AC21C39E939ACFF795e27b650F6e68': 7, + '0x692953e758c3669290cb1677180c64183cEe374e': 11, + '0x101816545F6bd2b1076434B54383a1E633390A2E': ETH_POOL_ID, + '0x590d4f8A68583639f215f675F3a259Ed84790580': 14, + '0xE8F55368C82D38bbbbDb5533e7F56AfC2E978CC2': 15, + '0x9cef9a0b1be0d289ac9f4a98ff317c33eaa84eb8': 16, + '0xd8772edBF88bBa2667ed011542343b0eDDaCDa47': 17, + '0x430Ebff5E3E80A6C58E7e6ADA1d90F5c28AA116d': 19, + }, + [BNB_LAYER_ZERO_CHAIN_ID]: { + '0x9aA83081AA06AF7208Dcc7A4cB72C94d057D2cda': 2, + '0x98a5737749490856b401DB5Dc27F522fC314A4e1': 5, + '0x4e145a589e4c03cBe3d28520e4BF3089834289Df': 11, + '0x7BfD7f2498C4796f10b6C611D9db393D3052510C': 16, + '0xD4CEc732b3B135eC52a3c0bc8Ce4b8cFb9dacE46': 17, + '0x68C6c27fB0e02285829e69240BE16f32C5f8bEFe': 19, + }, + [AVALANCHE_LAYER_ZERO_CHAIN_ID]: { + '0x1205f31718499dBf1fCa446663B532Ef87481fe1': 1, + '0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c': 2, + '0x1c272232Df0bb6225dA87f4dEcD9d37c32f63Eea': 7, + '0x8736f92646B2542B3e5F3c63590cA7Fe313e283B': 16, + '0xEAe5c2F6B25933deB62f754f239111413A0A25ef': 19, + }, + [POLYGON_LAYER_ZERO_CHAIN_ID]: { + '0x1205f31718499dBf1fCa446663B532Ef87481fe1': 1, + '0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c': 2, + '0x1c272232Df0bb6225dA87f4dEcD9d37c32f63Eea': 3, + '0x8736f92646B2542B3e5F3c63590cA7Fe313e283B': 16, + }, + [ARBITRUM_LAYER_ZERO_CHAIN_ID]: { + '0x892785f33CdeE22A30AEF750F285E18c18040c3e': 1, + '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9': 2, + '0xaa4BF442F024820B2C28Cd0FD72b82c63e66F56C': 7, + '0x82CbeCF39bEe528B5476FE6d1550af59a9dB6Fc0': ETH_POOL_ID, + '0x600E576F9d853c95d58029093A16EE49646F3ca5': 15, + '0xF39B7Be294cB36dE8c510e267B82bb588705d977': 16, + }, + [OPTIMISM_LAYER_ZERO_CHAIN_ID]: { + '0xDecC0c09c3B5f6e92EF4184125D5648a66E35298': 1, + '0x165137624F1f692e69659f944BF69DE02874ee27': 3, + '0x368605D9C6243A80903b9e326f1Cddde088B8924': 7, + '0xd22363e3762cA7339569F3d33EADe20127D5F98C': ETH_POOL_ID, + '0x2F8bC9081c7FCFeC25b9f41a50d97EaA592058ae': 14, + '0x3533F5e279bDBf550272a199a223dA798D9eff78': 15, + '0x5421FA1A48f9FF81e4580557E86C7C0D24C18036': 16, + }, + [FANTOM_LAYER_ZERO_CHAIN_ID]: { + '0xc647ce76ec30033aa319d472ae9f4462068f2ad7': 21, + }, + [METIS_LAYER_ZERO_CHAIN_ID]: { + '0xAad094F6A75A14417d39f04E690fC216f080A41a': 17, + '0x2b60473a7C41Deb80EDdaafD5560e963440eb632': 19, + }, + [KAVA_LAYER_ZERO_CHAIN_ID]: { + '0xAad094F6A75A14417d39f04E690fC216f080A41a': 2, + }, + [LINEA_LAYER_ZERO_CHAIN_ID]: { + '0xAad094F6A75A14417d39f04E690fC216f080A41a': ETH_POOL_ID, + }, + [BASE_LAYER_ZERO_CHAIN_ID]: { + '0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca': 1, + '0x28fc411f9e1c480AD312b3d9C60c22b965015c6B': ETH_POOL_ID, + }, +} + +export const CHAIN_AND_POOL_TO_TOKEN_ADDRESS: { + [chainId: number]: { [address: string]: number } +} = { + [ETH_LAYER_ZERO_CHAIN_ID]: { + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': USDC_POOL_ID, + '0xdAC17F958D2ee523a2206206994597C13D831ec7': USDT_POOL_ID, + '0x72E2F4830b9E45d52F80aC08CB2bEC0FeF72eD9c': ETH_POOL_ID, + }, + [BNB_LAYER_ZERO_CHAIN_ID]: { + '0x55d398326f99059fF775485246999027B3197955': USDT_POOL_ID, + }, + [AVALANCHE_LAYER_ZERO_CHAIN_ID]: { + '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e': USDC_POOL_ID, + '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7': USDT_POOL_ID, + }, + [POLYGON_LAYER_ZERO_CHAIN_ID]: { + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174': USDC_POOL_ID, + '0xc2132d05d31c914a87c6611c10748aeb04b58e8f': USDT_POOL_ID, + }, + [ARBITRUM_LAYER_ZERO_CHAIN_ID]: { + '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8': USDC_POOL_ID, + '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9': USDT_POOL_ID, + '0x82cbecf39bee528b5476fe6d1550af59a9db6fc0': ETH_POOL_ID, + }, + [OPTIMISM_LAYER_ZERO_CHAIN_ID]: { + '0x7f5c764cbc14f9669b88837ca1490cca17c31607': USDC_POOL_ID, + '0xb69c8cbcd90a39d8d3d3ccf0a3e968511c3856a0': ETH_POOL_ID, + }, + [KAVA_LAYER_ZERO_CHAIN_ID]: { + '0x919c1c267bc06a7039e03fcc2ef738525769109c': USDT_POOL_ID, + }, + [LINEA_LAYER_ZERO_CHAIN_ID]: { + '0x224d8fd7ab6ad4c6eb4611ce56ef35dec2277f03': ETH_POOL_ID, + }, + [BASE_LAYER_ZERO_CHAIN_ID]: { + '0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca': USDC_POOL_ID, + '0x224d8fd7ab6ad4c6eb4611ce56ef35dec2277f03': ETH_POOL_ID, + }, +} diff --git a/packages/stargate/src/get-token-from-pool.ts b/packages/stargate/src/get-token-from-pool.ts new file mode 100644 index 000000000..f9a127d9e --- /dev/null +++ b/packages/stargate/src/get-token-from-pool.ts @@ -0,0 +1,60 @@ +import { createPublicClient, http, type Address, type Chain } from 'viem' + +// The only way to get the token is to lookup the factory, lookup the pool, then lookup the token +export const getTokenFromPool = async ( + poolId: bigint, + chainId: number, + addr: Address, +) => { + const client = createPublicClient({ + chain: { + id: chainId, + } as Chain, + transport: http(), + }) + //Get Factory from Router + const factory = await client.readContract({ + address: addr, + abi: [ + { + inputs: [], + name: 'factory', + outputs: [ + { internalType: 'contract Factory', name: '', type: 'address' }, + ], + stateMutability: 'view', + type: 'function', + }, + ], + functionName: 'factory', + }) + // Get the pool from the factory + const pool = await client.readContract({ + address: factory, + abi: [ + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'getPool', + outputs: [{ internalType: 'contract Pool', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + ], + functionName: 'getPool', + args: [poolId], + }) + // Get the token from the pool + return await client.readContract({ + address: pool, + abi: [ + { + inputs: [], + name: 'token', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + ], + functionName: 'token', + }) +} diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts new file mode 100644 index 000000000..64afd3dd1 --- /dev/null +++ b/packages/stargate/src/index.ts @@ -0,0 +1,19 @@ +import { + type IActionPlugin, + PluginActionNotImplementedError, +} from '@rabbitholegg/questdk' + +import { + bridge, + getSupportedChainIds, + getSupportedTokenAddresses, +} from './Stargate.js' + +export const Stargate: IActionPlugin = { + pluginId: 'stargate', + getSupportedTokenAddresses, + getSupportedChainIds, + bridge, + swap: async () => new PluginActionNotImplementedError(), + mint: async () => new PluginActionNotImplementedError(), +} diff --git a/packages/stargate/src/test-transactions.ts b/packages/stargate/src/test-transactions.ts new file mode 100644 index 000000000..cb50a8358 --- /dev/null +++ b/packages/stargate/src/test-transactions.ts @@ -0,0 +1,96 @@ +export const DEPOSIT_ETH = { + type: 'eip1559', + blockHash: + '0x4906d090d3db3504e73ae5edd4b651b8ec046534dacc6a733c76113abbbe91bf', + blockNumber: '18079433', + from: '0x7c3bd1a09d7d86920451def20ae503322c8d0412', + gas: '457831', + hash: '0xe3a54ddf9a09ee9df6abe87af38cc418c516fb198fc635972615418f5254812a', + input: + '0x1114cd2a000000000000000000000000000000000000000000000000000000000000006e0000000000000000000000007c3bd1a09d7d86920451def20ae503322c8d041200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000009fdf42f6e48000000000000000000000000000000000000000000000000000009f12a011d1700000000000000000000000000000000000000000000000000000000000000000147c3bd1a09d7d86920451def20ae503322c8d0412000000000000000000000000', + nonce: 0, + to: '0x150f94b44927f078737562f0fcf3c95c01cc2376', + transactionIndex: 105, + value: '45972215017822948', + v: '1', + r: '0xd26a03d12aed46d5d560d7906e41e36ff4a989b906610c6105635719fe2167a0', + s: '0x1b6656d98851a5455bb2b98cd5e48c944330753fdda0c38886c38d9ed92f4fcb', + gasPrice: '24534329573', + maxFeePerGas: '32989778565', + maxPriorityFeePerGas: '100000000', + chainId: 1, + accessList: [], + typeHex: '0x2', +} +export const DEPOSIT_ERC20 = { + type: 'eip1559', + blockHash: + '0xf25e8e0a5284447a2a27ffefe924401a26851ccf52da879190d23cde1daf4876', + blockNumber: '18079378', + from: '0x0318ccfbfae5e2c06b2f533a35acecea13b9909f', + gas: '601475', + hash: '0x28901f729bd89400b5c046eb73abf0656ab82cb02463e47562d7ce24737d263f', + input: + '0x9fbf10fc000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000318ccfbfae5e2c06b2f533a35acecea13b9909f000000000000000000000000000000000000000000000000000000001cf96a3c000000000000000000000000000000000000000000000000000000001cd453f1000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000140318ccfbfae5e2c06b2f533a35acecea13b9909f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + nonce: 234, + to: '0x8731d54e9d02c286767d56ac03e8037c07e01e98', + transactionIndex: 44, + value: '972215017822948', + v: '0', + r: '0xb6b133280aeba72f9cf885bd3d3008c67086c7fd454b124ac08233bce9a16cc0', + s: '0x182f051e048b9b11ac84c44a7ccc7187fdce26bdf50a378fd7dc20c0e6a5b54b', + gasPrice: '25000000000', + maxFeePerGas: '25000000000', + maxPriorityFeePerGas: '2500000000', + chainId: 1, + accessList: [], + typeHex: '0x2', +} +export const WITHDRAW_ERC20 = { + blockHash: + '0xab8d99650aa499e42e0014f8915aedc77323a9552184707af75d5b848503372c', + blockNumber: '128685675', + from: '0x5ee8496532d3dcb8bc726d66d8cb4c45d979e71d', + gas: '1554359', + gasPrice: '100000000', + maxFeePerGas: '135000000', + maxPriorityFeePerGas: '0', + hash: '0xb983d41651ccad84a70600564376975a3a3385dae53de35259486f20dd2d8d4d', + input: + '0x9fbf10fc000000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000005ee8496532d3dcb8bc726d66d8cb4c45d979e71d000000000000000000000000000000000000000000000000000000004b6af220000000000000000000000000000000000000000000000000000000004b0a693c000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030927f74c9de0000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000145ee8496532d3dcb8bc726d66d8cb4c45d979e71d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000145ee8496532d3dcb8bc726d66d8cb4c45d979e71d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + nonce: 6, + to: '0x53bf833a5d6c4dda888f69c22c88c9f356a41614', + transactionIndex: 1, + value: '1650223662335887', + type: 'eip1559', + accessList: [], + chainId: 42161, + v: '1', + r: '0x297155d01bb11874c6d7d9a41bba09610e8cb5b9f85bf40bd8ea0306ddd5c110', + s: '0x32507907bce37aeaed981b72073d056d25a8003404adf24516651991976eea44', + typeHex: '0x2', +} +export const WITHDRAW_ETH = { + blockHash: + '0x65c72ed3a89fadd5c1d253285d626f19ca950b6efa05afa2e798289ea44876e0', + blockNumber: '128686656', + from: '0x08bfa4ef61a457792c45240829529b43b019d941', + gas: '1323525', + gasPrice: '100000000', + maxFeePerGas: '135000000', + maxPriorityFeePerGas: '0', + hash: '0xc6fa0deba78d6228d3cb343a908390162955dcb3d6d5a8e952ef24c54f7c453f', + input: + '0x1114cd2a000000000000000000000000000000000000000000000000000000000000006f00000000000000000000000008bfa4ef61a457792c45240829529b43b019d94100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000008700cc75770000000000000000000000000000000000000000000000000000008653fea2f520000000000000000000000000000000000000000000000000000000000000000001408bfa4ef61a457792c45240829529b43b019d941000000000000000000000000', + nonce: 47, + to: '0xbf22f0f184bccbea268df387a49ff5238dd23e40', + transactionIndex: 1, + value: '608597027570774601', + type: 'eip1559', + accessList: [], + chainId: 42161, + v: '1', + r: '0x8911dd94f10f4d18437c9035fe383702ec2b7888d599e525215b4e46b27a1881', + s: '0x1b05759abeb57de9edcde83b9e5da2987afdec8bff71f0863ad08574107aef6b', + typeHex: '0x2', +} diff --git a/packages/stargate/tsconfig.build.json b/packages/stargate/tsconfig.build.json new file mode 100644 index 000000000..2a80eac9f --- /dev/null +++ b/packages/stargate/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "tsconfig/base.json", + "include": ["src"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test-d.ts", + "src/**/*.bench.ts", + "src/_test", + "scripts/**/*" + ], + "compilerOptions": { + "resolveJsonModule": true, + "sourceMap": true, + "rootDir": "./src" + } +} diff --git a/packages/stargate/tsconfig.json b/packages/stargate/tsconfig.json new file mode 100644 index 000000000..5e14cb0d7 --- /dev/null +++ b/packages/stargate/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "tsconfig/base.json", + "include": ["src/**/*", "src/chain-data.ts"], + "exclude": ["dist", "build", "node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d05e885c6..bbbb4ac3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,6 +191,7 @@ importers: '@rabbitholegg/questdk-plugin-hop': workspace:* '@rabbitholegg/questdk-plugin-optimism': workspace:* '@rabbitholegg/questdk-plugin-polygon': workspace:* + '@rabbitholegg/questdk-plugin-stargate': workspace:* '@rabbitholegg/questdk-plugin-uniswap': workspace:* '@types/node': ^20.4.5 '@vitest/coverage-v8': ^0.33.0 @@ -209,6 +210,7 @@ importers: '@rabbitholegg/questdk-plugin-hop': link:../hop '@rabbitholegg/questdk-plugin-optimism': link:../optimism '@rabbitholegg/questdk-plugin-polygon': link:../polygon + '@rabbitholegg/questdk-plugin-stargate': link:../stargate '@rabbitholegg/questdk-plugin-uniswap': link:../uniswap viem: 1.10.14_typescript@5.2.2 devDependencies: @@ -221,6 +223,31 @@ importers: typescript: 5.2.2 vitest: 0.33.0 + packages/stargate: + specifiers: + '@rabbitholegg/questdk': 1.0.1-alpha.9 + '@types/node': 20.4.5 + '@vitest/coverage-v8': 0.33.0 + rimraf: 5.0.1 + rome: 12.1.3 + ts-node: 10.9.1 + tsconfig: workspace:* + typescript: 5.1.6 + viem: 1.6.7 + vitest: 0.33.0 + dependencies: + '@rabbitholegg/questdk': 1.0.1-alpha.9_typescript@5.1.6 + viem: 1.6.7_typescript@5.1.6 + devDependencies: + '@types/node': 20.4.5 + '@vitest/coverage-v8': 0.33.0_vitest@0.33.0 + rimraf: 5.0.1 + rome: 12.1.3 + ts-node: 10.9.1_bir6x3g64ycygfv3l4v3letmxi + tsconfig: link:../tsconfig + typescript: 5.1.6 + vitest: 0.33.0 + packages/template: specifiers: '@rabbitholegg/questdk': 1.0.1-alpha.8 @@ -2134,7 +2161,7 @@ packages: /@scure/bip39/1.2.0: resolution: {integrity: sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==} dependencies: - '@noble/hashes': 1.3.0 + '@noble/hashes': 1.3.1 '@scure/base': 1.1.3 dev: false @@ -2787,6 +2814,17 @@ packages: typescript: 5.1.6 dev: false + /@wagmi/chains/1.7.0_typescript@5.1.6: + resolution: {integrity: sha512-TKVeHv0GqP5sV1yQ8BDGYToAFezPnCexbbBpeH14x7ywi5a1dDStPffpt9x+ytE6LJWkZ6pAMs/HNWXBQ5Nqmw==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.1.6 + dev: false + /abitype/0.8.11_typescript@5.1.6: resolution: {integrity: sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A==} peerDependencies: @@ -2799,6 +2837,20 @@ packages: typescript: 5.1.6 dev: false + /abitype/0.9.3_typescript@5.1.6: + resolution: {integrity: sha512-dz4qCQLurx97FQhnb/EIYTk/ldQ+oafEDUqC0VVIeQS1Q48/YWt/9YNfMmp9SLFqN41ktxny3c8aYxHjmFIB/w==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.19.1 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + dependencies: + typescript: 5.1.6 + dev: false + /abitype/0.9.8_typescript@5.1.6: resolution: {integrity: sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==} peerDependencies: @@ -9555,6 +9607,31 @@ packages: - zod dev: false + /viem/1.6.7_typescript@5.1.6: + resolution: {integrity: sha512-w2OMJqKcQrzPQnmMFxe4ex+md8wSwfle6L3LvEi25CBvDKhkuljVrsWY19UzG05ssQhiZ+cdxU3YMBrX817Qiw==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@adraffy/ens-normalize': 1.9.0 + '@noble/curves': 1.1.0 + '@noble/hashes': 1.3.0 + '@scure/bip32': 1.3.0 + '@scure/bip39': 1.2.0 + '@types/ws': 8.5.5 + '@wagmi/chains': 1.7.0_typescript@5.1.6 + abitype: 0.9.3_typescript@5.1.6 + isomorphic-ws: 5.0.0_ws@8.12.0 + typescript: 5.1.6 + ws: 8.12.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + dev: false + /vite-node/0.33.0_@types+node@20.4.5: resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==} engines: {node: '>=v14.18.0'}