diff --git a/packages/extension/package.json b/packages/extension/package.json index d4d53c8f6..245b6edee 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -80,7 +80,6 @@ "@chakra-ui/icons": "^2.0.15", "@argent/stack-router": "^5.2.0", "@argent/ui": "^5.2.0", - "@argent/x-multicall": "^5.2.0", "@extend-chrome/messages": "^1.2.2", "@google/model-viewer": "^2.0.0", "@mui/icons-material": "^5.3.1", diff --git a/packages/extension/src/shared/multicall/getMulticall.ts b/packages/extension/src/shared/multicall/getMulticall.ts deleted file mode 100644 index 12135211a..000000000 --- a/packages/extension/src/shared/multicall/getMulticall.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Multicall } from "@argent/x-multicall" -import { memoize } from "lodash-es" - -import { Network, getProvider } from "../network" - -export class NoMulticallAddressError extends Error { - constructor(message?: string) { - super(message) - this.name = "NoMulticallAddressError" - } -} diff --git a/packages/extension/src/shared/multicall/index.ts b/packages/extension/src/shared/multicall/index.ts deleted file mode 100644 index e5d89497c..000000000 --- a/packages/extension/src/shared/multicall/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./getMulticall" diff --git a/packages/extension/src/ui/features/accounts/upgrade.service.ts b/packages/extension/src/ui/features/accounts/upgrade.service.ts index 3fcb86f83..3fbe831de 100644 --- a/packages/extension/src/ui/features/accounts/upgrade.service.ts +++ b/packages/extension/src/ui/features/accounts/upgrade.service.ts @@ -1,4 +1,3 @@ -import { Multicall } from "@argent/x-multicall" import { partition } from "lodash-es" import { number } from "starknet" import useSWR from "swr" diff --git a/packages/multicall/.eslintrc.json b/packages/multicall/.eslintrc.json deleted file mode 100644 index 66709acb2..000000000 --- a/packages/multicall/.eslintrc.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true, - "node": true - }, - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": ["@typescript-eslint"], - "rules": { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-extra-semi": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "vars": "all", - "ignoreRestSiblings": true, - "argsIgnorePattern": "^_" - } - ], - "@typescript-eslint/no-non-null-assertion": "error", - "curly": "error" - } -} diff --git a/packages/multicall/README.md b/packages/multicall/README.md deleted file mode 100644 index e8ee939bb..000000000 --- a/packages/multicall/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Multicall - -This library allows you to make multiple calls to a contract in a single network request. diff --git a/packages/multicall/__tests__/integration.test.ts b/packages/multicall/__tests__/integration.test.ts deleted file mode 100644 index 286044f03..000000000 --- a/packages/multicall/__tests__/integration.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { SequencerProvider } from "starknet" -import { uint256 } from "starknet" -import { beforeAll, describe, expect, test } from "vitest" - -import { Multicall } from ".." - -describe.each([ - { - // Test with default provider on testnet2 and default multicall contract address - baseUrl: "https://alpha4-2.starknet.io/", - multicallAddress: undefined, - }, - { - // Test with default provider on testnet2 and not deployed multicall contract address (should fallback to one request per call) - baseUrl: "https://alpha4-2.starknet.io/", - multicallAddress: "0xdead", - }, -])( - "Multicall with address $multicallAddress", - ({ baseUrl, multicallAddress }) => { - let mc: Multicall - beforeAll(() => { - mc = new Multicall( - new SequencerProvider({ - baseUrl, - }), - multicallAddress, - { - batchInterval: 10, // 10ms - }, - ) - }) - - test("should aggregate multiple calls into one multicall", async () => { - const results = await Promise.all([ - // promises resolve at the same time as they use multicall contract - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "balanceOf", - calldata: [ - "0x04a79cA7FDE3dd9C5CBadcBDCB39f95A0619da26767af0B52fD0901cd556a035".toLowerCase(), - ], - }), - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "balanceOf", - calldata: [ - "0x0472eb42746E4b7b426B6DC45B9ac0345bA38502d0928209016F8a1323330CF4".toLowerCase(), - ], - }), - ]) - - for (const result of results) { - const [low, high] = result - const balance = uint256.uint256ToBN({ low, high }) - expect(balance.gt(0)).toBeTruthy() - } - }) - test("should partially error with a single error", async () => { - const results = await Promise.allSettled([ - // promises resolve at the same time as they use multicall contract - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "balanceOf", - calldata: [ - "0x0472eb42746E4b7b426B6DC45B9ac0345bA38502d0928209016F8a1323330CF4".toLowerCase(), - ], - }), - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "get_balance", // this will fail - calldata: [ - "0x04a79cA7FDE3dd9C5CBadcBDCB39f95A0619da26767af0B52fD0901cd556a035".toLowerCase(), - ], - }), - ]) - - expect(results.map((x) => x.status)).toMatchInlineSnapshot(` - [ - "fulfilled", - "rejected", - ] - `) - }) - test("should partially error with multiple errors", async () => { - const results = await Promise.allSettled([ - // promises resolve at the same time as they use multicall contract - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "get_balance", // this will fail - calldata: [ - "0x0472eb42746E4b7b426B6DC45B9ac0345bA38502d0928209016F8a1323330CF4".toLowerCase(), - ], - }), - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "balanceOf", - calldata: [ - "0x0472eb42746E4b7b426B6DC45B9ac0345bA38502d0928209016F8a1323330CF4".toLowerCase(), - ], - }), - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "get_balance", // this will fail - calldata: [ - "0x04a79cA7FDE3dd9C5CBadcBDCB39f95A0619da26767af0B52fD0901cd556a035".toLowerCase(), - ], - }), - ]) - - expect(results.map((x) => x.status)).toMatchInlineSnapshot(` - [ - "rejected", - "fulfilled", - "rejected", - ] - `) - }) - test("should error when all fail", async () => { - const results = await Promise.allSettled([ - // promises resolve at the same time as they use multicall contract - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "get_balance", // this will fail - calldata: [ - "0x0472eb42746E4b7b426B6DC45B9ac0345bA38502d0928209016F8a1323330CF4".toLowerCase(), - ], - }), - mc.call({ - contractAddress: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - entrypoint: "get_balance", // this will fail - calldata: [ - "0x04a79cA7FDE3dd9C5CBadcBDCB39f95A0619da26767af0B52fD0901cd556a035".toLowerCase(), - ], - }), - ]) - - expect(results.map((x) => x.status)).toMatchInlineSnapshot(` - [ - "rejected", - "rejected", - ] - `) - }) - }, -) diff --git a/packages/multicall/package.json b/packages/multicall/package.json deleted file mode 100644 index b022e38f0..000000000 --- a/packages/multicall/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@argent/x-multicall", - "version": "5.2.0", - "description": "A library for batched calls to Starknet smart contracts", - "keywords": [ - "starknet", - "starkware", - "multicall", - "argent", - "argentx", - "wallet", - "dapp" - ], - "author": "Janek Rahrt ", - "homepage": "https://github.com/argentlabs/argent-x/tree/main/packages/multicall#readme", - "license": "GPL-3.0-only", - "type": "module", - "exports": { - ".": { - "import": "./dist/multicall.js", - "require": "./dist/multicall.umd.cjs" - } - }, - "main": "./dist/multicall.umd.cjs", - "module": "./dist/multicall.js", - "types": "./dist/multicall.d.ts", - "files": [ - "dist" - ], - "publishConfig": { - "registry": "https://registry.npmjs.org" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/argentlabs/argent-x.git" - }, - "scripts": { - "test": "vitest run", - "test:watch": "vitest", - "dev": "vite build --watch", - "prepare": "vite build", - "build": "vite build" - }, - "bugs": { - "url": "https://github.com/argentlabs/argent-x/issues" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.0.0", - "happy-dom": "^8.1.0", - "vite": "^4.0.3", - "vite-plugin-dts": "^1.4.1", - "vitest": "^0.27.1" - }, - "dependencies": { - "dataloader": "^2.1.0", - "starknet": "^4.19.3" - } -} diff --git a/packages/multicall/src/aggregate.ts b/packages/multicall/src/aggregate.ts deleted file mode 100644 index 2f09b9009..000000000 --- a/packages/multicall/src/aggregate.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - Call, - GatewayError, - ProviderInterface, - number, - stark, - transaction, -} from "starknet" - -const partitionResponses = (responses: string[]): string[][] => { - if (responses.length === 0) { - return [] - } - - const [responseLength, ...restResponses] = responses - const responseLengthInt = number.toBN(responseLength).toNumber() - const response = restResponses.slice(0, responseLengthInt) - const remainingResponses = restResponses.slice(responseLengthInt) - - return [response, ...partitionResponses(remainingResponses)] -} - -const extractErrorCallIndex = (e: Error) => { - try { - const errorCallIndex = (e as any) - .toString() - .match(/Error message: multicall (\d+) failed/)?.[1] - if (errorCallIndex === undefined) { - throw e - } - return parseInt(errorCallIndex, 10) - } catch { - throw e - } -} - -const fallbackAggregate = async ( - provider: ProviderInterface, - calls: Call[], -): Promise<(string[] | Error)[]> => { - const results = await Promise.allSettled( - calls.map((call) => - provider - .callContract({ - contractAddress: call.contractAddress, - entrypoint: call.entrypoint, - calldata: stark.compileCalldata(call.calldata ?? []), - }) - .then((res) => res.result), - ), - ) - - return results.map((result) => { - if (result.status === "fulfilled") { - return result.value - } - return result.reason - }) -} - -export const aggregate = async ( - provider: ProviderInterface, - multicallAddress: string, - calls: Call[], -): Promise<(string[] | Error)[]> => { - if (calls.length === 0) { - return [] - } - try { - const res = await provider.callContract({ - contractAddress: multicallAddress, - entrypoint: "aggregate", - calldata: transaction.fromCallsToExecuteCalldata([...calls]), - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_blockNumber, _totalLength, ...results] = res.result - - return partitionResponses(results) - } catch (e) { - if (!(e instanceof Error)) { - throw e - } - - if ( - e instanceof GatewayError && - e.errorCode === "StarknetErrorCode.UNINITIALIZED_CONTRACT" - ) { - return fallbackAggregate(provider, calls) - } - - const errorCallIndex = extractErrorCallIndex(e) - const remainingCalls = calls.filter((_, i) => i !== errorCallIndex) - const remainingResults = await aggregate( - provider, - multicallAddress, - remainingCalls, - ) - return [ - ...remainingResults.slice(0, errorCallIndex), - e, - ...remainingResults.slice(errorCallIndex), - ] - } -} diff --git a/packages/multicall/src/dataloader.ts b/packages/multicall/src/dataloader.ts deleted file mode 100644 index fe8788f6c..000000000 --- a/packages/multicall/src/dataloader.ts +++ /dev/null @@ -1,43 +0,0 @@ -import DataLoader from "dataloader" -import { Call, ProviderInterface, hash, number } from "starknet" - -import { aggregate } from "./aggregate" - -export interface DataLoaderOptions { - maxBatchSize?: number - batchInterval?: number -} - -export const getDataLoader = ( - provider: ProviderInterface, - multicallAddress: string, - options: DataLoaderOptions = { - batchInterval: 500, - maxBatchSize: 10, - }, -) => { - const dl = new DataLoader( - async (calls: readonly Call[]): Promise<(string[] | Error)[]> => { - dl.clearAll() - return aggregate(provider, multicallAddress, calls as Call[]) - }, - { - maxBatchSize: options.maxBatchSize, - batchScheduleFn(callback) { - setTimeout(callback, options.batchInterval) - }, - cacheKeyFn(call) { - const { contractAddress, entrypoint, calldata = [] } = call - const cacheKeyContractAddress = number.toHex( - number.toBN(contractAddress), - ) - const cacheKeyEntrypoint = hash.getSelector(entrypoint) - const cacheKeyCalldata = calldata - .map((c) => number.toHex(number.toBN(c))) - .join("-") - return `${cacheKeyContractAddress}--${cacheKeyEntrypoint}--${cacheKeyCalldata}` - }, - }, - ) - return dl -} diff --git a/packages/multicall/src/main.ts b/packages/multicall/src/main.ts deleted file mode 100644 index 0d4ffce0e..000000000 --- a/packages/multicall/src/main.ts +++ /dev/null @@ -1,23 +0,0 @@ -import DataLoader from "dataloader" -import { Call, ProviderInterface } from "starknet" - -import { DataLoaderOptions, getDataLoader } from "./dataloader" - -const DEFAULT_MULTICALL_ADDRESS = - "0x05754af3760f3356da99aea5c3ec39ccac7783d925a19666ebbeca58ff0087f4" - -export class Multicall { - public readonly dataloader: DataLoader - - constructor( - public readonly provider: ProviderInterface, - public readonly address: string = DEFAULT_MULTICALL_ADDRESS, - dataLoaderOptions?: DataLoaderOptions, - ) { - this.dataloader = getDataLoader(provider, address, dataLoaderOptions) - } - - public call(call: Call): Promise { - return this.dataloader.load(call) - } -} diff --git a/packages/multicall/tsconfig.json b/packages/multicall/tsconfig.json deleted file mode 100644 index ce50f5a64..000000000 --- a/packages/multicall/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", - "strict": true, - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "declaration": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/multicall/vite.config.ts b/packages/multicall/vite.config.ts deleted file mode 100644 index eca063eb6..000000000 --- a/packages/multicall/vite.config.ts +++ /dev/null @@ -1,39 +0,0 @@ -// vite.config.js -import { resolve as resolvePath } from "path" - -import dts from "vite-plugin-dts" -import { defineConfig } from "vitest/config" - -export default defineConfig({ - build: { - rollupOptions: { - external: ["starknet"], - output: { - exports: "named", - }, - }, - emptyOutDir: false, - lib: { - entry: resolvePath(__dirname, "src/main.ts"), - name: "multicall", - // the proper extensions will be added - fileName: "multicall", - }, - }, - optimizeDeps: { - include: ["starknet"], - }, - plugins: [ - dts({ - entryRoot: resolvePath(__dirname, "src"), - insertTypesEntry: true, - }), - ], - test: { - environment: "happy-dom", - exclude: ["**/node_modules/**", "**/*.mock.ts"], - coverage: { - exclude: ["**/node_modules/**", "**/*.mock.ts"], - }, - }, -}) diff --git a/yarn.lock b/yarn.lock index f0e1b910e..942344f13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5261,18 +5261,6 @@ is-module "^1.0.0" resolve "^1.19.0" -"@rollup/plugin-node-resolve@^15.0.0": - version "15.0.1" - resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz" - integrity sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - "@types/resolve" "1.20.2" - deepmerge "^4.2.2" - is-builtin-module "^3.2.0" - is-module "^1.0.0" - resolve "^1.22.1" - "@rollup/plugin-replace@^2.4.1": version "2.4.2" resolved "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz" @@ -5306,7 +5294,7 @@ estree-walker "^2.0.1" picomatch "^2.2.2" -"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.0.2": +"@rollup/pluginutils@^5.0.2": version "5.0.2" resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz" integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA== @@ -7588,11 +7576,6 @@ dependencies: "@types/node" "*" -"@types/resolve@1.20.2": - version "1.20.2" - resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz" - integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== - "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz" @@ -11296,11 +11279,6 @@ css-what@^6.0.1: resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== -css.escape@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz" - integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== - cssdb@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz" @@ -11434,11 +11412,6 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -dataloader@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.1.0.tgz" - integrity sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ== - date-fns@^2.29.1: version "2.29.3" resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz" @@ -14148,18 +14121,6 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -happy-dom@^8.1.0: - version "8.1.2" - resolved "https://registry.npmjs.org/happy-dom/-/happy-dom-8.1.2.tgz" - integrity sha512-A/mTzD6KiVMWZynne7R+HlZjIpz9a1Ijh99inqq51Vis1v4G1K+mQeyOo19TXHtoFwAdjx+PzXQGpcyV0yhy9Q== - dependencies: - css.escape "^1.5.1" - he "^1.2.0" - node-fetch "^2.x.x" - webidl-conversions "^7.0.0" - whatwg-encoding "^2.0.0" - whatwg-mimetype "^3.0.0" - hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" @@ -15036,7 +14997,7 @@ is-buffer@^2.0.0: resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-builtin-module@^3.0.0, is-builtin-module@^3.1.0, is-builtin-module@^3.2.0: +is-builtin-module@^3.0.0, is-builtin-module@^3.1.0: version "3.2.0" resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz" integrity sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw== @@ -18116,7 +18077,7 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" -node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.x.x: +node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -24003,7 +23964,7 @@ vite-node@0.27.1: source-map-support "^0.5.21" vite "^3.0.0 || ^4.0.0" -vite-plugin-dts@^1.4.1, vite-plugin-dts@^1.6.6: +vite-plugin-dts@^1.6.6: version "1.7.1" resolved "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-1.7.1.tgz" integrity sha512-2oGMnAjcrZN7jM1TloiS1b1mCn42s3El04ix2RFhId5P1WfMigF8WAwsqT6a6jk0Yso8t7AeZsBkkxYShR0hBQ==