From 365435f36acb49064254b4e7bc2cb8ff4246e8c7 Mon Sep 17 00:00:00 2001 From: Himanshu Singroha Date: Tue, 16 Dec 2025 15:14:43 +0530 Subject: [PATCH] feat: added support for ftm Ticket: COIN-6857 TICKET: COIN-6857 --- modules/bitgo/src/v2/coinFactory.ts | 6 +++++ .../test/fixtures/ethlikeCoin.ts | 13 +++++++++++ .../sdk-coin-ethlike/test/unit/ethlikeCoin.ts | 4 ++++ modules/sdk-core/src/bitgo/environments.ts | 4 ++++ modules/statics/src/allCoinsAndTokens.ts | 20 +++++++++++++++++ modules/statics/src/base.ts | 2 ++ modules/statics/src/networks.ts | 22 +++++++++++++++++++ .../unit/fixtures/expectedColdFeatures.ts | 2 ++ 8 files changed, 73 insertions(+) diff --git a/modules/bitgo/src/v2/coinFactory.ts b/modules/bitgo/src/v2/coinFactory.ts index 5b1a4e2555..157d81b05e 100644 --- a/modules/bitgo/src/v2/coinFactory.ts +++ b/modules/bitgo/src/v2/coinFactory.ts @@ -260,9 +260,11 @@ export function registerCoinConstructors(coinFactory: CoinFactory, coinMap: Coin coinFactory.register('ethw', Ethw.createInstance); coinFactory.register('baseeth', EthLikeCoin.createInstance); coinFactory.register('opbnb', EthLikeCoin.createInstance); + coinFactory.register('fantom', EthLikeCoin.createInstance); coinFactory.register('og', EthLikeCoin.createInstance); coinFactory.register('tog', EthLikeCoin.createInstance); coinFactory.register('topbnb', TethLikeCoin.createInstance); + coinFactory.register('tfantom', TethLikeCoin.createInstance); coinFactory.register('tbaseeth', TethLikeCoin.createInstance); coinFactory.register('fiataed', FiatAED.createInstance); coinFactory.register('fiateur', FiatEur.createInstance); @@ -645,10 +647,14 @@ export function getCoinConstructor(coinName: string): CoinConstructor | undefine return EthLikeCoin.createInstance; case 'opbnb': return EthLikeCoin.createInstance; + case 'fantom': + return EthLikeCoin.createInstance; case 'tbaseeth': return TethLikeCoin.createInstance; case 'topbnb': return TethLikeCoin.createInstance; + case 'tfantom': + return TethLikeCoin.createInstance; case 'fiataed': return FiatAED.createInstance; case 'fiateur': diff --git a/modules/sdk-coin-ethlike/test/fixtures/ethlikeCoin.ts b/modules/sdk-coin-ethlike/test/fixtures/ethlikeCoin.ts index 03284c055f..ffbcf0dd9b 100644 --- a/modules/sdk-coin-ethlike/test/fixtures/ethlikeCoin.ts +++ b/modules/sdk-coin-ethlike/test/fixtures/ethlikeCoin.ts @@ -75,6 +75,11 @@ export const ccr = { '0x02f901d38215eb01843b9aca00843b9aca00830186a0948ce59c2d1702844f8eded451aa103961bc37b4e880b90164391252150000000000000000000000002c2b9c9a4a25e24b174f26114e8926a9f2128fe40000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000006939c792000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041833fbbdb8457ee22924b2ad59becbd1629481ca2bf10b9c66dba45e6fbd8fe1f62fc94c6a3a0a8915abe7df7ce9cf2b3d43b0e46f539d11f00cbe9c5aa2dfbe71c00000000000000000000000000000000000000000000000000000000000000c080a05614c8ae83fee9c0d95334114103aa4fee94f574dd55497f41f532d98ce95100a0102dbe65dcd4034fbf2c2e997758180f15e8c626fb9df4f1695a7fa01dbb376e', txid: '0x48052a9408a20f317b938dbcd7c30c6019c19571ed07ded11853bae9f16493fd', }, + tfantom: { + txHex: + '0x02f901d3820fa201843b9aca00843b9aca00830186a0948ce59c2d1702844f8eded451aa103961bc37b4e880b90164391252150000000000000000000000002c2b9c9a4a25e24b174f26114e8926a9f2128fe40000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000006939c792000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041833fbbdb8457ee22924b2ad59becbd1629481ca2bf10b9c66dba45e6fbd8fe1f62fc94c6a3a0a8915abe7df7ce9cf2b3d43b0e46f539d11f00cbe9c5aa2dfbe71c00000000000000000000000000000000000000000000000000000000000000c080a05614c8ae83fee9c0d95334114103aa4fee94f574dd55497f41f532d98ce95100a0102dbe65dcd4034fbf2c2e997758180f15e8c626fb9df4f1695a7fa01dbb376e', + txid: '0x58062b9508b30f417c948ebce7d30d6029d29681fe17eed21963cbe9f26593fe', + }, }; export const encryptedUserKey = '{"iv":"VFZ3jvXhxo1Z+Yaf2MtZnA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' + @@ -107,4 +112,12 @@ export const custodialHot = { signedTxHex: '0xf9016a80830186a082520894702cf81e03aa310ec9481d814e3d04a20b04b50580b901440dcd7a6c000000000000000000000000b9f62c71d5f6949cfb211a67fb13ccf079cc760b0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000e4ab69c077896252fafbd49efd26b5d171a324100000000000000000000000000000000000000000000000000000000067f415e1000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041a9c3ead37547fa56b694e4eccc9352225b7458ef08e4e961ca5774d398abd55b5986a7446259374d2098012923583935189739f18dd117c4d15221b2a26f50911c00000000000000000000000000000000000000000000000000000000000000822bf98080', }, + tfantom: { + signatureData: + '0dcd7a6c00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000b9f62c71d5f6949cfb211a67fb13ccf079cc760b0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000e4ab69c077896252fafbd49efd26b5d171a324100000000000000000000000000000000000000000000000000000000067f415e10000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000a343030322d45524332300000000000000000000000000000000000000000000000', + signature: + '0xa9c3ead37547fa56b694e4eccc9352225b7458ef08e4e961ca5774d398abd55b5986a7446259374d2098012923583935189739f18dd117c4d15221b2a26f50911c', + signedTxHex: + '0xf9016a80830186a082520894702cf81e03aa310ec9481d814e3d04a20b04b50580b901440dcd7a6c000000000000000000000000b9f62c71d5f6949cfb211a67fb13ccf079cc760b0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000e4ab69c077896252fafbd49efd26b5d171a324100000000000000000000000000000000000000000000000000000000067f415e1000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041a9c3ead37547fa56b694e4eccc9352225b7458ef08e4e961ca5774d398abd55b5986a7446259374d2098012923583935189739f18dd117c4d15221b2a26f50911c00000000000000000000000000000000000000000000000000000000000000821f678080', + }, }; diff --git a/modules/sdk-coin-ethlike/test/unit/ethlikeCoin.ts b/modules/sdk-coin-ethlike/test/unit/ethlikeCoin.ts index 0e7fdd68e4..d55a8205fc 100644 --- a/modules/sdk-coin-ethlike/test/unit/ethlikeCoin.ts +++ b/modules/sdk-coin-ethlike/test/unit/ethlikeCoin.ts @@ -26,6 +26,10 @@ const coins = [ name: 'topbnb', common: getCommon('topbnb'), }, + { + name: 'tfantom', + common: getCommon('tfantom'), + }, ]; describe('EthLike coin tests', function () { diff --git a/modules/sdk-core/src/bitgo/environments.ts b/modules/sdk-core/src/bitgo/environments.ts index 0968f0b3c9..47fd4be3f9 100644 --- a/modules/sdk-core/src/bitgo/environments.ts +++ b/modules/sdk-core/src/bitgo/environments.ts @@ -265,6 +265,10 @@ const mainnetBase: EnvironmentTemplate = { baseUrl: 'https://api.etherscan.io/v2', apiToken: process.env.ETHERSCAN_API_TOKEN, }, + fantom: { + baseUrl: 'https://explorer.fantom.network', + rpcUrl: 'https://rpcapi.fantom.network/', + }, flow: { baseUrl: 'https://evm.flowscan.io', }, diff --git a/modules/statics/src/allCoinsAndTokens.ts b/modules/statics/src/allCoinsAndTokens.ts index d7e4bcde0a..b807f866bc 100644 --- a/modules/statics/src/allCoinsAndTokens.ts +++ b/modules/statics/src/allCoinsAndTokens.ts @@ -447,6 +447,26 @@ export const allCoinsAndTokens = [ BaseUnit.ETH, [...ETH_FEATURES, CoinFeature.USES_NON_PACKED_ENCODING_FOR_TXDATA, CoinFeature.EIP1559] ), + account( + 'a97b6e81-33fb-4f63-83b6-7ca91e95f8b4', + 'tfantom', + 'Fantom Testnet', + Networks.test.fantom, + 18, + UnderlyingAsset.FANTOM, + BaseUnit.ETH, + [...ETH_FEATURES, CoinFeature.USES_NON_PACKED_ENCODING_FOR_TXDATA, CoinFeature.EIP1559] + ), + account( + '06178542-d2e1-4626-bd46-6a4aaa45415e', + 'fantom', + 'Fantom Mainnet', + Networks.main.fantom, + 18, + UnderlyingAsset.FANTOM, + BaseUnit.ETH, + [...ETH_FEATURES, CoinFeature.USES_NON_PACKED_ENCODING_FOR_TXDATA, CoinFeature.EIP1559] + ), account( 'ffc472f5-27c6-49f8-ad9a-f57659258fb9', 'etc', diff --git a/modules/statics/src/base.ts b/modules/statics/src/base.ts index 8d547bf29f..1942e6aaa2 100644 --- a/modules/statics/src/base.ts +++ b/modules/statics/src/base.ts @@ -57,6 +57,7 @@ export enum CoinFamily { FETCHAI = 'fetchai', FIAT = 'fiat', FLOW = 'flow', + FANTOM = 'fantom', // Fantom FLR = 'flr', FLRP = 'flrp', HASH = 'hash', // Provenance @@ -571,6 +572,7 @@ export enum UnderlyingAsset { FLR = 'flr', FLRP = 'flrp', FLUENTETH = 'fluenteth', + FANTOM = 'fantom', // Fantom GTC = 'gtc', HASH = 'hash', // Provenance HBAR = 'hbar', // Hedera main coin diff --git a/modules/statics/src/networks.ts b/modules/statics/src/networks.ts index d374f750b4..296d211088 100644 --- a/modules/statics/src/networks.ts +++ b/modules/statics/src/networks.ts @@ -398,6 +398,26 @@ class OpBNBTestnet extends Testnet implements EthereumNetwork { tokenOperationHashPrefix = '5611-ERC20'; } +class Fantom extends Mainnet implements EthereumNetwork { + name = 'Fantom'; + family = CoinFamily.FANTOM; + explorerUrl = 'https://explorer.fantom.network/transactions/'; + accountExplorerUrl = 'https://explorer.fantom.network/address/'; + chainId = 250; + nativeCoinOperationHashPrefix = '250'; + tokenOperationHashPrefix = '250-ERC20'; +} + +class FantomTestnet extends Testnet implements EthereumNetwork { + name = 'FantomTestnet'; + family = CoinFamily.FANTOM; + explorerUrl = 'https://explorer.fantom.network/transactions/'; + accountExplorerUrl = 'https://explorer.fantom.network/address/'; + chainId = 4002; + nativeCoinOperationHashPrefix = '4002'; + tokenOperationHashPrefix = '4002-ERC20'; +} + class LightningBitcoin extends Mainnet implements LightningNetwork { name = 'LightningBitcoin'; family = CoinFamily.LNBTC; @@ -2274,6 +2294,7 @@ export const Networks = { ofc: Object.freeze(new Ofc()), okb: Object.freeze(new Xlayer()), opbnb: Object.freeze(new OpBNB()), + fantom: Object.freeze(new Fantom()), morph: Object.freeze(new Morph()), optimism: Object.freeze(new Optimism()), osmo: Object.freeze(new Osmo()), @@ -2382,6 +2403,7 @@ export const Networks = { ofc: Object.freeze(new OfcTestnet()), okb: Object.freeze(new XlayerTestnet()), opbnb: Object.freeze(new OpBNBTestnet()), + fantom: Object.freeze(new FantomTestnet()), morph: Object.freeze(new MorphTestnet()), optimism: Object.freeze(new OptimismTestnet()), osmo: Object.freeze(new OsmoTestnet()), diff --git a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts index 02fa758eaf..66d5403227 100644 --- a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts +++ b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts @@ -202,6 +202,8 @@ export const expectedColdFeatures = { ], neither: [ 'ethw', + 'fantom', + 'tfantom', 'opbnb', 'topbnb', 'fiataed',