From 273365cf12343d106fc0fce84535580762888fc2 Mon Sep 17 00:00:00 2001 From: Hitansh Madan Date: Wed, 4 Jun 2025 11:40:46 +0530 Subject: [PATCH] feat: add sdk-coin-evm Ticket: WIN-5511 --- CODEOWNERS | 1 + Dockerfile | 3 + modules/account-lib/package.json | 1 + modules/account-lib/src/index.ts | 15 +++- .../account-lib/test/unit/keyPair/index.ts | 2 +- modules/account-lib/tsconfig.json | 3 + modules/bitgo/package.json | 1 + modules/bitgo/src/v2/coinFactory.ts | 9 ++- modules/bitgo/src/v2/coins/index.ts | 2 + modules/bitgo/test/browser/browser.spec.ts | 1 + modules/bitgo/tsconfig.json | 3 + modules/sdk-coin-evm/.eslintignore | 1 + modules/sdk-coin-evm/.gitignore | 3 + modules/sdk-coin-evm/.mocharc.yml | 8 +++ modules/sdk-coin-evm/.npmignore | 12 ++++ modules/sdk-coin-evm/.prettierignore | 2 + modules/sdk-coin-evm/.prettierrc.yml | 3 + modules/sdk-coin-evm/CHANGELOG.md | 4 ++ modules/sdk-coin-evm/README.md | 3 + modules/sdk-coin-evm/package.json | 49 +++++++++++++ modules/sdk-coin-evm/src/evm.ts | 68 +++++++++++++++++++ modules/sdk-coin-evm/src/index.ts | 3 + modules/sdk-coin-evm/src/lib/index.ts | 6 ++ .../src/lib/transactionBuilder.ts | 36 ++++++++++ .../sdk-coin-evm/src/lib/transferBuilder.ts | 1 + modules/sdk-coin-evm/src/lib/utils.ts | 29 ++++++++ modules/sdk-coin-evm/src/register.ts | 11 +++ modules/sdk-coin-evm/test/unit/evmCoin.ts | 0 modules/sdk-coin-evm/tsconfig.json | 12 ++++ modules/sdk-core/src/bitgo/environments.ts | 6 ++ modules/statics/src/base.ts | 5 ++ tsconfig.packages.json | 3 + yarn.lock | 6 +- 33 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 modules/sdk-coin-evm/.eslintignore create mode 100644 modules/sdk-coin-evm/.gitignore create mode 100644 modules/sdk-coin-evm/.mocharc.yml create mode 100644 modules/sdk-coin-evm/.npmignore create mode 100644 modules/sdk-coin-evm/.prettierignore create mode 100644 modules/sdk-coin-evm/.prettierrc.yml create mode 100644 modules/sdk-coin-evm/CHANGELOG.md create mode 100644 modules/sdk-coin-evm/README.md create mode 100644 modules/sdk-coin-evm/package.json create mode 100644 modules/sdk-coin-evm/src/evm.ts create mode 100644 modules/sdk-coin-evm/src/index.ts create mode 100644 modules/sdk-coin-evm/src/lib/index.ts create mode 100644 modules/sdk-coin-evm/src/lib/transactionBuilder.ts create mode 100644 modules/sdk-coin-evm/src/lib/transferBuilder.ts create mode 100644 modules/sdk-coin-evm/src/lib/utils.ts create mode 100644 modules/sdk-coin-evm/src/register.ts create mode 100644 modules/sdk-coin-evm/test/unit/evmCoin.ts create mode 100644 modules/sdk-coin-evm/tsconfig.json diff --git a/CODEOWNERS b/CODEOWNERS index b7a9f2e74b..5062764cbf 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -62,6 +62,7 @@ /modules/sdk-coin-cspr/ @BitGo/ethalt-team /modules/sdk-coin-dot/ @BitGo/ethalt-team /modules/sdk-coin-eos/ @BitGo/ethalt-team +/modules/sdk-coin-evm/ @BitGo/ethalt-team /modules/sdk-coin-fetchai/ @BitGo/ethalt-team /modules/sdk-coin-flr/ @BitGo/ethalt-team /modules/sdk-coin-ethlike/ @BitGo/ethalt-team diff --git a/Dockerfile b/Dockerfile index 99f5c0a44e..f3696af20a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,6 +66,7 @@ COPY --from=builder /tmp/bitgo/modules/abstract-cosmos /var/modules/abstract-cos COPY --from=builder /tmp/bitgo/modules/sdk-coin-avaxc /var/modules/sdk-coin-avaxc/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-avaxp /var/modules/sdk-coin-avaxp/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-eth /var/modules/sdk-coin-eth/ +COPY --from=builder /tmp/bitgo/modules/sdk-coin-evm /var/modules/sdk-coin-evm/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-baby /var/modules/sdk-coin-baby/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bera /var/modules/sdk-coin-bera/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bld /var/modules/sdk-coin-bld/ @@ -159,6 +160,7 @@ cd /var/modules/abstract-cosmos && yarn link && \ cd /var/modules/sdk-coin-avaxc && yarn link && \ cd /var/modules/sdk-coin-avaxp && yarn link && \ cd /var/modules/sdk-coin-eth && yarn link && \ +cd /var/modules/sdk-coin-evm && yarn link && \ cd /var/modules/sdk-coin-baby && yarn link && \ cd /var/modules/sdk-coin-bera && yarn link && \ cd /var/modules/sdk-coin-bld && yarn link && \ @@ -255,6 +257,7 @@ RUN cd /var/bitgo-express && \ yarn link @bitgo/sdk-coin-avaxc && \ yarn link @bitgo/sdk-coin-avaxp && \ yarn link @bitgo/sdk-coin-eth && \ + yarn link @bitgo/sdk-coin-evm && \ yarn link @bitgo/sdk-coin-baby && \ yarn link @bitgo/sdk-coin-bera && \ yarn link @bitgo/sdk-coin-bld && \ diff --git a/modules/account-lib/package.json b/modules/account-lib/package.json index a5ec954e16..cd068e0e85 100644 --- a/modules/account-lib/package.json +++ b/modules/account-lib/package.json @@ -46,6 +46,7 @@ "@bitgo/sdk-coin-dot": "^4.2.0", "@bitgo/sdk-coin-etc": "^2.2.50", "@bitgo/sdk-coin-eth": "^24.5.0", + "@bitgo/sdk-coin-evm": "^1.0.0", "@bitgo/sdk-coin-fetchai": "^2.0.2", "@bitgo/sdk-coin-flr": "^1.2.7", "@bitgo/sdk-coin-hash": "^3.0.52", diff --git a/modules/account-lib/src/index.ts b/modules/account-lib/src/index.ts index c417204d99..14111b0aaa 100644 --- a/modules/account-lib/src/index.ts +++ b/modules/account-lib/src/index.ts @@ -8,7 +8,7 @@ import { accountLibBaseCoin, acountLibCrypto, } from '@bitgo/sdk-core'; -import { BaseCoin as CoinConfig, coins } from '@bitgo/statics'; +import { BaseCoin as CoinConfig, coins, CoinFeature } from '@bitgo/statics'; export { Ed25519BIP32, Eddsa }; /** @@ -191,6 +191,9 @@ export { Stt }; import * as Soneium from '@bitgo/sdk-coin-soneium'; export { Soneium }; +import * as EvmCoin from '@bitgo/sdk-coin-evm'; +export { EvmCoin }; + const coinBuilderMap = { trx: Trx.WrappedBuilder, ttrx: Trx.WrappedBuilder, @@ -303,6 +306,16 @@ const coinBuilderMap = { tpolyx: Polyx.TransactionBuilderFactory, }; +/** + * coins.filter(coin => coin.coinFeature.has(EVM_SHARED_SDK)).forEach(coin => coinBuilderMap[coin.name] = EvmCoin.TransactionBuilder); + */ + +coins + .filter((coin) => coin.features.includes(CoinFeature.SHARED_EVM_SDK)) + .forEach((coin) => { + coinBuilderMap[coin.name] = EvmCoin.TransactionBuilder; + }); + /** * Get the list of coin tickers supported by this library. */ diff --git a/modules/account-lib/test/unit/keyPair/index.ts b/modules/account-lib/test/unit/keyPair/index.ts index 570c513af2..bba9eccac5 100644 --- a/modules/account-lib/test/unit/keyPair/index.ts +++ b/modules/account-lib/test/unit/keyPair/index.ts @@ -12,7 +12,7 @@ describe('Key Pair Factory', () => { describe('coinToKey map initialization', function () { const supportedCoinsExceptTestnet = Object.keys(coinModules) // TODO(BG-40990): temporarily disable eth2 from the test for bls not initialized error - .filter((k) => coinModules[k].KeyPair && k.trim().toLowerCase() !== 'eth2'); + .filter((k) => coinModules[k].KeyPair && !['eth2', 'evmcoin'].includes(k.trim().toLowerCase())); supportedCoinsExceptTestnet.forEach((coinName) => { it(`should initialize a ${coinName} keyPair map`, () => { diff --git a/modules/account-lib/tsconfig.json b/modules/account-lib/tsconfig.json index dd58f93c74..f64ef544da 100644 --- a/modules/account-lib/tsconfig.json +++ b/modules/account-lib/tsconfig.json @@ -49,6 +49,9 @@ { "path": "../sdk-coin-eth" }, + { + "path": "../sdk-coin-evm" + }, { "path": "../sdk-coin-flr" }, diff --git a/modules/bitgo/package.json b/modules/bitgo/package.json index ab26230eb0..7fe98800b3 100644 --- a/modules/bitgo/package.json +++ b/modules/bitgo/package.json @@ -79,6 +79,7 @@ "@bitgo/sdk-coin-eth": "^24.5.0", "@bitgo/sdk-coin-ethlike": "^1.2.18", "@bitgo/sdk-coin-ethw": "^20.0.83", + "@bitgo/sdk-coin-evm": "^1.0.0", "@bitgo/sdk-coin-fetchai": "^2.0.2", "@bitgo/sdk-coin-flr": "^1.2.7", "@bitgo/sdk-coin-hash": "^3.0.52", diff --git a/modules/bitgo/src/v2/coinFactory.ts b/modules/bitgo/src/v2/coinFactory.ts index ca544dab64..0aa02715f7 100644 --- a/modules/bitgo/src/v2/coinFactory.ts +++ b/modules/bitgo/src/v2/coinFactory.ts @@ -9,7 +9,7 @@ import { Near, TNear } from '@bitgo/sdk-coin-near'; import { SolToken } from '@bitgo/sdk-coin-sol'; import { TrxToken } from '@bitgo/sdk-coin-trx'; import { CoinFactory } from '@bitgo/sdk-core'; -import { CoinMap, coins, getFormattedTokens } from '@bitgo/statics'; +import { CoinFeature, CoinMap, coins, getFormattedTokens } from '@bitgo/statics'; import { Ada, Algo, @@ -49,6 +49,7 @@ import { Eth, Ethw, EthLikeCoin, + EvmCoin, FetchAi, Flr, TethLikeCoin, @@ -345,6 +346,12 @@ export function registerCoinConstructors(coinFactory: CoinFactory, coinMap: Coin coinFactory.register('zeta', Zeta.createInstance); coinFactory.register('zketh', Zketh.createInstance); + coins + .filter((coin) => coin.features.includes(CoinFeature.SHARED_EVM_SDK)) + .forEach((coin) => { + coinFactory.register(coin.name, EvmCoin.createInstance); + }); + const tokens = getFormattedTokens(coinMap); Erc20Token.createTokenConstructors([...tokens.bitcoin.eth.tokens, ...tokens.testnet.eth.tokens]).forEach( diff --git a/modules/bitgo/src/v2/coins/index.ts b/modules/bitgo/src/v2/coins/index.ts index 94805fd7ad..53ec924a0c 100644 --- a/modules/bitgo/src/v2/coins/index.ts +++ b/modules/bitgo/src/v2/coins/index.ts @@ -31,6 +31,7 @@ import { Erc20Token, Eth, Gteth, Hteth, Teth } from '@bitgo/sdk-coin-eth'; import { FetchAi, TfetchAi } from '@bitgo/sdk-coin-fetchai'; import { Flr, Tflr } from '@bitgo/sdk-coin-flr'; import { Ethw } from '@bitgo/sdk-coin-ethw'; +import { EvmCoin } from '@bitgo/sdk-coin-evm'; import { EthLikeCoin, TethLikeCoin } from '@bitgo/sdk-coin-ethlike'; import { Hash, Thash } from '@bitgo/sdk-coin-hash'; import { Hbar, Thbar } from '@bitgo/sdk-coin-hbar'; @@ -102,6 +103,7 @@ export { Erc20Token, Eth, Gteth, Hteth, Teth }; export { Ethw }; export { EthLikeCoin, TethLikeCoin }; export { Etc, Tetc }; +export { EvmCoin }; export { FetchAi, TfetchAi }; export { Flr, Tflr }; export { Hash, Thash }; diff --git a/modules/bitgo/test/browser/browser.spec.ts b/modules/bitgo/test/browser/browser.spec.ts index e7835a4cae..c8e561f1bf 100644 --- a/modules/bitgo/test/browser/browser.spec.ts +++ b/modules/bitgo/test/browser/browser.spec.ts @@ -43,6 +43,7 @@ describe('Coins', () => { Polyx: 1, Tpolyx: 1, CoredaoToken: 1, + EvmCoin: 1, }; Object.keys(BitGoJS.Coin) .filter((coinName) => !excludedKeys[coinName]) diff --git a/modules/bitgo/tsconfig.json b/modules/bitgo/tsconfig.json index f6ed6ad396..514606fef0 100644 --- a/modules/bitgo/tsconfig.json +++ b/modules/bitgo/tsconfig.json @@ -149,6 +149,9 @@ { "path": "../sdk-coin-ethw" }, + { + "path": "../sdk-coin-evm" + }, { "path": "../sdk-coin-fetchai" }, diff --git a/modules/sdk-coin-evm/.eslintignore b/modules/sdk-coin-evm/.eslintignore new file mode 100644 index 0000000000..849ddff3b7 --- /dev/null +++ b/modules/sdk-coin-evm/.eslintignore @@ -0,0 +1 @@ +dist/ diff --git a/modules/sdk-coin-evm/.gitignore b/modules/sdk-coin-evm/.gitignore new file mode 100644 index 0000000000..67ccce4c64 --- /dev/null +++ b/modules/sdk-coin-evm/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.idea/ +dist/ diff --git a/modules/sdk-coin-evm/.mocharc.yml b/modules/sdk-coin-evm/.mocharc.yml new file mode 100644 index 0000000000..b2cacd8968 --- /dev/null +++ b/modules/sdk-coin-evm/.mocharc.yml @@ -0,0 +1,8 @@ +require: 'ts-node/register' +timeout: '60000' +reporter: 'min' +reporter-option: + - 'cdn=true' + - 'json=false' +exit: true +spec: ['test/**/*.ts'] diff --git a/modules/sdk-coin-evm/.npmignore b/modules/sdk-coin-evm/.npmignore new file mode 100644 index 0000000000..7df125fca2 --- /dev/null +++ b/modules/sdk-coin-evm/.npmignore @@ -0,0 +1,12 @@ +!dist/ +.idea/ +.prettierrc.yml +tsconfig.json +src/ +test/ +scripts/ +.nyc_output +CODEOWNERS +node_modules/ +.prettierignore +.mocharc.js diff --git a/modules/sdk-coin-evm/.prettierignore b/modules/sdk-coin-evm/.prettierignore new file mode 100644 index 0000000000..3a11d6af29 --- /dev/null +++ b/modules/sdk-coin-evm/.prettierignore @@ -0,0 +1,2 @@ +.nyc_output/ +dist/ diff --git a/modules/sdk-coin-evm/.prettierrc.yml b/modules/sdk-coin-evm/.prettierrc.yml new file mode 100644 index 0000000000..7c3d8dd32a --- /dev/null +++ b/modules/sdk-coin-evm/.prettierrc.yml @@ -0,0 +1,3 @@ +printWidth: 120 +singleQuote: true +trailingComma: 'es5' diff --git a/modules/sdk-coin-evm/CHANGELOG.md b/modules/sdk-coin-evm/CHANGELOG.md new file mode 100644 index 0000000000..e4d87c4d45 --- /dev/null +++ b/modules/sdk-coin-evm/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/modules/sdk-coin-evm/README.md b/modules/sdk-coin-evm/README.md new file mode 100644 index 0000000000..7c96b88462 --- /dev/null +++ b/modules/sdk-coin-evm/README.md @@ -0,0 +1,3 @@ +# @bitgo/sdk-coin-evm + +Configurable common module for EVM assets, using @bitgo/abstract-eth for reduced coin integration boilerplate diff --git a/modules/sdk-coin-evm/package.json b/modules/sdk-coin-evm/package.json new file mode 100644 index 0000000000..8432466476 --- /dev/null +++ b/modules/sdk-coin-evm/package.json @@ -0,0 +1,49 @@ +{ + "name": "@bitgo/sdk-coin-evm", + "version": "1.0.0", + "description": "Configurable common module for EVM assets, using @bitgo/abstract-eth for reduced coin integration boilerplate.", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "scripts": { + "build": "yarn tsc --build --incremental --verbose .", + "fmt": "prettier --write .", + "check-fmt": "prettier --check .", + "clean": "rm -r ./dist", + "lint": "eslint --quiet .", + "test": "npm run coverage", + "coverage": "nyc -- npm run unit-test", + "unit-test": "mocha", + "prepare": "npm run build" + }, + "dependencies": { + "@bitgo/abstract-eth": "^24.4.0", + "@bitgo/sdk-core": "^35.1.0", + "@bitgo/statics": "^54.1.0", + "@ethereumjs/common": "^2.6.5" + }, + "devDependencies": {}, + "author": "BitGo SDK Team ", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/BitGo/BitGoJS.git", + "directory": "modules/sdk-coin-evm" + }, + "files": [ + "dist/src" + ], + "lint-staged": { + "*.{js,ts}": [ + "yarn prettier --write", + "yarn eslint --fix" + ] + }, + "publishConfig": { + "access": "public" + }, + "nyc": { + "extension": [ + ".ts" + ] + } +} diff --git a/modules/sdk-coin-evm/src/evm.ts b/modules/sdk-coin-evm/src/evm.ts new file mode 100644 index 0000000000..90de95f665 --- /dev/null +++ b/modules/sdk-coin-evm/src/evm.ts @@ -0,0 +1,68 @@ +/** + * @prettier + */ +import { BaseCoin, BitGoBase, common, MPCAlgorithm, MultisigType, multisigTypes } from '@bitgo/sdk-core'; +import { BaseCoin as StaticsBaseCoin, CoinFeature, coins } from '@bitgo/statics'; +import { + AbstractEthLikeNewCoins, + OfflineVaultTxInfo, + RecoverOptions, + recoveryBlockchainExplorerQuery, + TransactionBuilder as EthLikeTransactionBuilder, + UnsignedSweepTxMPCv2, +} from '@bitgo/abstract-eth'; +import { TransactionBuilder } from './lib'; +import assert from 'assert'; + +export class EvmCoin extends AbstractEthLikeNewCoins { + protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { + super(bitgo, staticsCoin); + } + + static createInstance(bitgo: BitGoBase, staticsCoin?: Readonly): BaseCoin { + return new EvmCoin(bitgo, staticsCoin); + } + + protected getTransactionBuilder(): EthLikeTransactionBuilder { + return new TransactionBuilder(coins.get(this.getBaseChain())); + } + + /** @inheritDoc */ + supportsTss(): boolean { + return this.staticsCoin?.features.includes(CoinFeature.TSS) ?? false; + } + + /** inherited doc */ + getDefaultMultisigType(): MultisigType { + return this.staticsCoin?.features.includes(CoinFeature.TSS) ? multisigTypes.tss : multisigTypes.onchain; + } + + /** @inheritDoc */ + getMPCAlgorithm(): MPCAlgorithm { + return 'ecdsa'; + } + + protected async buildUnsignedSweepTxnTSS(params: RecoverOptions): Promise { + if (this.staticsCoin?.features.includes(CoinFeature.MPCV2)) { + return this.buildUnsignedSweepTxnMPCv2(params); + } + return super.buildUnsignedSweepTxnTSS(params); + } + + /** + * Make a query to chain explorer for information such as balance, token balance, solidity calls + * @param {Object} query key-value pairs of parameters to append after /api + * @returns {Promise} response from chain explorer + */ + async recoveryBlockchainExplorerQuery(query: Record): Promise> { + const evmConfig = common.Environments[this.bitgo.getEnv()].evm; + assert( + evmConfig && this.getFamily() in evmConfig, + `env config is missing for ${this.getFamily()} in ${this.bitgo.getEnv()}` + ); + + const apiToken = evmConfig[this.getFamily()].apiToken; + const explorerUrl = evmConfig[this.getFamily()].baseUrl; + return await recoveryBlockchainExplorerQuery(query, explorerUrl as string, apiToken as string); + } +} diff --git a/modules/sdk-coin-evm/src/index.ts b/modules/sdk-coin-evm/src/index.ts new file mode 100644 index 0000000000..973643ac42 --- /dev/null +++ b/modules/sdk-coin-evm/src/index.ts @@ -0,0 +1,3 @@ +export * from './evm'; +export * from './lib'; +export * from './register'; diff --git a/modules/sdk-coin-evm/src/lib/index.ts b/modules/sdk-coin-evm/src/lib/index.ts new file mode 100644 index 0000000000..20f9e761a1 --- /dev/null +++ b/modules/sdk-coin-evm/src/lib/index.ts @@ -0,0 +1,6 @@ +import * as Utils from './utils'; + +export { TransactionBuilder } from './transactionBuilder'; +export { TransferBuilder } from './transferBuilder'; +export { Transaction, KeyPair } from '@bitgo/abstract-eth'; +export { Utils }; diff --git a/modules/sdk-coin-evm/src/lib/transactionBuilder.ts b/modules/sdk-coin-evm/src/lib/transactionBuilder.ts new file mode 100644 index 0000000000..3a245844a4 --- /dev/null +++ b/modules/sdk-coin-evm/src/lib/transactionBuilder.ts @@ -0,0 +1,36 @@ +import { BaseCoin as CoinConfig } from '@bitgo/statics'; +import { BuildTransactionError, TransactionType } from '@bitgo/sdk-core'; +import { TransactionBuilder as AbstractTransactionBuilder, Transaction } from '@bitgo/abstract-eth'; +import { getCommon } from './utils'; +import { TransferBuilder } from './transferBuilder'; + +export class TransactionBuilder extends AbstractTransactionBuilder { + protected _transfer: TransferBuilder; + private _signatures: any; + + constructor(_coinConfig: Readonly) { + super(_coinConfig); + this._common = getCommon(this._coinConfig); + this.transaction = new Transaction(this._coinConfig, this._common); + } + + /** @inheritdoc */ + transfer(data?: string): TransferBuilder { + if (this._type !== TransactionType.Send) { + throw new BuildTransactionError('Transfers can only be set for send transactions'); + } + if (!this._transfer) { + this._transfer = new TransferBuilder(data); + } + return this._transfer; + } + + addSignature(publicKey, signature) { + this._signatures = []; + this._signatures.push({ publicKey, signature }); + } + + protected getContractData(addresses: string[]): string { + throw new Error('Method not implemented.'); + } +} diff --git a/modules/sdk-coin-evm/src/lib/transferBuilder.ts b/modules/sdk-coin-evm/src/lib/transferBuilder.ts new file mode 100644 index 0000000000..7447c0cf3d --- /dev/null +++ b/modules/sdk-coin-evm/src/lib/transferBuilder.ts @@ -0,0 +1 @@ +export { TransferBuilder } from '@bitgo/abstract-eth'; diff --git a/modules/sdk-coin-evm/src/lib/utils.ts b/modules/sdk-coin-evm/src/lib/utils.ts new file mode 100644 index 0000000000..0e9ce9a2c3 --- /dev/null +++ b/modules/sdk-coin-evm/src/lib/utils.ts @@ -0,0 +1,29 @@ +import { CoinFeature, NetworkType, BaseCoin, EthereumNetwork } from '@bitgo/statics'; +import EthereumCommon from '@ethereumjs/common'; +import { InvalidTransactionError } from '@bitgo/sdk-core'; + +/** + * @param {NetworkType} network either mainnet or testnet + * @returns {EthereumCommon} Ethereum common configuration object + */ +export function getCommon(coin: Readonly): EthereumCommon { + if (!coin.features.includes(CoinFeature.SHARED_EVM_SDK)) { + throw new InvalidTransactionError(`Cannot use common sdk module for the coin ${coin.name}`); + } + + if (!coin.features.includes(CoinFeature.SHARED_EVM_SDK)) { + throw new InvalidTransactionError(`Cannot use common sdk module for the coin ${coin.name}`); + } + return EthereumCommon.custom( + { + name: coin.network.name, + networkId: (coin.network as EthereumNetwork).chainId, + chainId: (coin.network as EthereumNetwork).chainId, + }, + { + baseChain: coin.network.type === NetworkType.MAINNET ? 'mainnet' : 'sepolia', + hardfork: coin.features.includes(CoinFeature.EIP1559) ? 'london' : undefined, + eips: coin.features.includes(CoinFeature.EIP1559) ? [1559] : undefined, + } + ); +} diff --git a/modules/sdk-coin-evm/src/register.ts b/modules/sdk-coin-evm/src/register.ts new file mode 100644 index 0000000000..81acd9130a --- /dev/null +++ b/modules/sdk-coin-evm/src/register.ts @@ -0,0 +1,11 @@ +import { BitGoBase } from '@bitgo/sdk-core'; +import { CoinFeature, coins } from '@bitgo/statics'; +import { EvmCoin } from './evm'; + +export const register = (sdk: BitGoBase): void => { + coins + .filter((coin) => coin.features.includes(CoinFeature.SHARED_EVM_SDK)) + .forEach((coin) => { + sdk.register(coin.name, EvmCoin.createInstance); + }); +}; diff --git a/modules/sdk-coin-evm/test/unit/evmCoin.ts b/modules/sdk-coin-evm/test/unit/evmCoin.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/sdk-coin-evm/tsconfig.json b/modules/sdk-coin-evm/tsconfig.json new file mode 100644 index 0000000000..9a4e1ca6ba --- /dev/null +++ b/modules/sdk-coin-evm/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./", + "strictPropertyInitialization": false, + "esModuleInterop": true, + "typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/modules/sdk-core/src/bitgo/environments.ts b/modules/sdk-core/src/bitgo/environments.ts index 196bc713d3..c7aedcc7b5 100644 --- a/modules/sdk-core/src/bitgo/environments.ts +++ b/modules/sdk-core/src/bitgo/environments.ts @@ -85,6 +85,12 @@ interface EnvironmentTemplate { soneiumExplorerApiToken?: string; stxNodeUrl: string; vetNodeUrl: string; + evm?: { + [key: string]: { + baseUrl: string; + apiToken?: string; + }; + }; } export interface Environment extends EnvironmentTemplate { diff --git a/modules/statics/src/base.ts b/modules/statics/src/base.ts index 33a12c5e6d..d8dbd38a99 100644 --- a/modules/statics/src/base.ts +++ b/modules/statics/src/base.ts @@ -365,6 +365,11 @@ export enum CoinFeature { */ SHARED_EVM_SIGNING = 'shared-evm-signing', + /** + * This coin is an EVM compatible coin and should use common EVM SDK module + */ + SHARED_EVM_SDK = 'shared-evm-sdk', + /** * This coin supports multisig wallets */ diff --git a/tsconfig.packages.json b/tsconfig.packages.json index 3c2e0add5c..2f5f0b470d 100644 --- a/tsconfig.packages.json +++ b/tsconfig.packages.json @@ -127,6 +127,9 @@ { "path": "./modules/sdk-coin-ethw" }, + { + "path": "./modules/sdk-coin-evm" + }, { "path": "./modules/sdk-coin-fetchai" }, diff --git a/yarn.lock b/yarn.lock index 1619963ec3..38288e2b29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21228,6 +21228,6 @@ yocto-queue@^1.0.0: integrity sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg== zod@^3.21.4: - version "3.24.2" - resolved "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz#8efa74126287c675e92f46871cfc8d15c34372b3" - integrity sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ== + version "3.25.51" + resolved "https://registry.npmjs.org/zod/-/zod-3.25.51.tgz#aa2cf648e54f6f060f139cf77b694819f63c9f3a" + integrity sha512-TQSnBldh+XSGL+opiSIq0575wvDPqu09AqWe1F7JhUMKY+M91/aGlK4MhpVNO7MgYfHcVCB1ffwAUTJzllKJqg==