From 84d4a3c205e0a98f3ab5288d22dc86e82f4d44e7 Mon Sep 17 00:00:00 2001 From: Shubham Damkondwar Date: Tue, 12 May 2026 20:35:25 +0530 Subject: [PATCH] feat(sdk-coin-starknet): scaffold @bitgo/sdk-coin-starknet package Skeleton sdk-coin-starknet module for Starknet L2. - New package modules/sdk-coin-starknet with Starknet/Tstarknet coin classes extending BaseCoin; ECDSA TSS (secp256k1, shouldHash=false deferred to CECHO-926) - Statics: CoinFamily.STARKNET, UnderlyingAsset.STARKNET (separate from existing STRK ERC-20), BaseUnit.STARKNET='fri', StarknetNetwork / StarknetTestnet classes, allCoinsAndTokens entries (18 decimals, secp256k1), STARKNET_FEATURES - Monorepo wiring: bitgo coinFactory, coins/index, tsconfigs, Dockerfile Builders, address derivation, signing, and RPC client land in CECHO-925/926/927. CECHO-924 TICKET: CECHO-924 --- Dockerfile | 3 + modules/bitgo/package.json | 1 + modules/bitgo/src/v2/coinFactory.ts | 8 ++ modules/bitgo/src/v2/coins/index.ts | 2 + modules/bitgo/test/browser/browser.spec.ts | 2 + modules/bitgo/tsconfig.json | 3 + modules/sdk-coin-starknet/.eslintignore | 4 + modules/sdk-coin-starknet/.gitignore | 3 + modules/sdk-coin-starknet/.mocharc.yml | 8 ++ modules/sdk-coin-starknet/.npmignore | 14 +++ modules/sdk-coin-starknet/.prettierignore | 2 + modules/sdk-coin-starknet/.prettierrc.yml | 3 + modules/sdk-coin-starknet/README.md | 32 +++++ modules/sdk-coin-starknet/package.json | 51 ++++++++ modules/sdk-coin-starknet/src/index.ts | 3 + modules/sdk-coin-starknet/src/register.ts | 8 ++ modules/sdk-coin-starknet/src/starknet.ts | 113 ++++++++++++++++++ modules/sdk-coin-starknet/src/tstarknet.ts | 25 ++++ .../test/integration/index.ts | 0 modules/sdk-coin-starknet/test/unit/index.ts | 35 ++++++ modules/sdk-coin-starknet/tsconfig.json | 26 ++++ modules/sdk-core/src/bitgo/environments.ts | 3 + modules/statics/src/allCoinsAndTokens.ts | 23 ++++ modules/statics/src/base.ts | 3 + modules/statics/src/coinFeatures.ts | 9 ++ modules/statics/src/networks.ts | 16 +++ .../unit/fixtures/expectedColdFeatures.ts | 2 + tsconfig.packages.json | 3 + 28 files changed, 405 insertions(+) create mode 100644 modules/sdk-coin-starknet/.eslintignore create mode 100644 modules/sdk-coin-starknet/.gitignore create mode 100644 modules/sdk-coin-starknet/.mocharc.yml create mode 100644 modules/sdk-coin-starknet/.npmignore create mode 100644 modules/sdk-coin-starknet/.prettierignore create mode 100644 modules/sdk-coin-starknet/.prettierrc.yml create mode 100644 modules/sdk-coin-starknet/README.md create mode 100644 modules/sdk-coin-starknet/package.json create mode 100644 modules/sdk-coin-starknet/src/index.ts create mode 100644 modules/sdk-coin-starknet/src/register.ts create mode 100644 modules/sdk-coin-starknet/src/starknet.ts create mode 100644 modules/sdk-coin-starknet/src/tstarknet.ts create mode 100644 modules/sdk-coin-starknet/test/integration/index.ts create mode 100644 modules/sdk-coin-starknet/test/unit/index.ts create mode 100644 modules/sdk-coin-starknet/tsconfig.json diff --git a/Dockerfile b/Dockerfile index b0ab9be760..ca5000dffc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -140,6 +140,7 @@ COPY --from=builder /tmp/bitgo/modules/sdk-coin-ethw /var/modules/sdk-coin-ethw/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-iota /var/modules/sdk-coin-iota/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-lnbtc /var/modules/sdk-coin-lnbtc/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-ltc /var/modules/sdk-coin-ltc/ +COPY --from=builder /tmp/bitgo/modules/sdk-coin-starknet /var/modules/sdk-coin-starknet/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-xlm /var/modules/sdk-coin-xlm/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-zec /var/modules/sdk-coin-zec/ @@ -242,6 +243,7 @@ cd /var/modules/sdk-coin-ethw && yarn link && \ cd /var/modules/sdk-coin-iota && yarn link && \ cd /var/modules/sdk-coin-lnbtc && yarn link && \ cd /var/modules/sdk-coin-ltc && yarn link && \ +cd /var/modules/sdk-coin-starknet && yarn link && \ cd /var/modules/sdk-coin-xlm && yarn link && \ cd /var/modules/sdk-coin-zec && yarn link #COPY_END @@ -347,6 +349,7 @@ RUN cd /var/bitgo-express && \ yarn link @bitgo/sdk-coin-iota && \ yarn link @bitgo/sdk-coin-lnbtc && \ yarn link @bitgo/sdk-coin-ltc && \ + yarn link @bitgo/sdk-coin-starknet && \ yarn link @bitgo/sdk-coin-xlm && \ yarn link @bitgo/sdk-coin-zec #LINK_END diff --git a/modules/bitgo/package.json b/modules/bitgo/package.json index 3b4e49b15f..b85696d37b 100644 --- a/modules/bitgo/package.json +++ b/modules/bitgo/package.json @@ -107,6 +107,7 @@ "@bitgo/sdk-coin-sgb": "^1.8.7", "@bitgo/sdk-coin-sol": "^7.19.2", "@bitgo/sdk-coin-soneium": "^1.10.7", + "@bitgo/sdk-coin-starknet": "^1.0.0", "@bitgo/sdk-coin-stt": "^1.6.7", "@bitgo/sdk-coin-stx": "^3.12.7", "@bitgo/sdk-coin-sui": "^5.23.6", diff --git a/modules/bitgo/src/v2/coinFactory.ts b/modules/bitgo/src/v2/coinFactory.ts index c08b4adad1..943f6ffbe5 100644 --- a/modules/bitgo/src/v2/coinFactory.ts +++ b/modules/bitgo/src/v2/coinFactory.ts @@ -127,6 +127,7 @@ import { Sol, Soneium, SoneiumToken, + Starknet, StellarToken, Stx, Sui, @@ -191,6 +192,7 @@ import { Tsei, Tsol, Tsoneium, + Tstarknet, Tstx, Tstt, Tsui, @@ -298,6 +300,7 @@ export function registerCoinConstructors(coinFactory: CoinFactory, coinMap: Coin coinFactory.register('sgb', Sgb.createInstance); coinFactory.register('sol', Sol.createInstance); coinFactory.register('soneium', Soneium.createInstance); + coinFactory.register('starknet', Starknet.createInstance); coinFactory.register('stx', Stx.createInstance); coinFactory.register('sui', Sui.createInstance); coinFactory.register('susd', Susd.createInstance); @@ -363,6 +366,7 @@ export function registerCoinConstructors(coinFactory: CoinFactory, coinMap: Coin coinFactory.register('tsei', Tsei.createInstance); coinFactory.register('tsol', Tsol.createInstance); coinFactory.register('tsoneium', Tsoneium.createInstance); + coinFactory.register('tstarknet', Tstarknet.createInstance); coinFactory.register('tstx', Tstx.createInstance); coinFactory.register('tstt', Tstt.createInstance); coinFactory.register('tsui', Tsui.createInstance); @@ -735,6 +739,8 @@ export function getCoinConstructor(coinName: string): CoinConstructor | undefine return Sol.createInstance; case 'soneium': return Soneium.createInstance; + case 'starknet': + return Starknet.createInstance; case 'stx': return Stx.createInstance; case 'sui': @@ -865,6 +871,8 @@ export function getCoinConstructor(coinName: string): CoinConstructor | undefine return Tsol.createInstance; case 'tsoneium': return Tsoneium.createInstance; + case 'tstarknet': + return Tstarknet.createInstance; case 'tstx': return Tstx.createInstance; case 'tstt': diff --git a/modules/bitgo/src/v2/coins/index.ts b/modules/bitgo/src/v2/coins/index.ts index 9a6607a8da..0ab8ef15a2 100644 --- a/modules/bitgo/src/v2/coins/index.ts +++ b/modules/bitgo/src/v2/coins/index.ts @@ -56,6 +56,7 @@ import { Rbtc, Trbtc } from '@bitgo/sdk-coin-rbtc'; import { Rune, Trune } from '@bitgo/sdk-coin-rune'; import { Sei, Tsei } from '@bitgo/sdk-coin-sei'; import { Soneium, Tsoneium, SoneiumToken } from '@bitgo/sdk-coin-soneium'; +import { Starknet, Tstarknet } from '@bitgo/sdk-coin-starknet'; import { Tstt } from '@bitgo/sdk-coin-stt'; import { Sgb, Tsgb } from '@bitgo/sdk-coin-sgb'; import { Sol, Tsol } from '@bitgo/sdk-coin-sol'; @@ -133,6 +134,7 @@ export { Rune, Trune }; export { Sgb, Tsgb }; export { Sol, Tsol }; export { Soneium, Tsoneium, SoneiumToken }; +export { Starknet, Tstarknet }; export { Tstt }; export { Stx, Tstx, Sip10Token }; export { Sui, Tsui, SuiToken }; diff --git a/modules/bitgo/test/browser/browser.spec.ts b/modules/bitgo/test/browser/browser.spec.ts index 71cdbeb86f..7f788957b5 100644 --- a/modules/bitgo/test/browser/browser.spec.ts +++ b/modules/bitgo/test/browser/browser.spec.ts @@ -61,6 +61,8 @@ describe('Coins', () => { MonToken: 1, XdcToken: 1, JettonToken: 1, + Starknet: 1, + Tstarknet: 1, Tip20Token: 1, Fiat: 1, allFiatCoins: 1, diff --git a/modules/bitgo/tsconfig.json b/modules/bitgo/tsconfig.json index 8c16adaaf4..26c3e3d8c2 100644 --- a/modules/bitgo/tsconfig.json +++ b/modules/bitgo/tsconfig.json @@ -230,6 +230,9 @@ { "path": "../sdk-coin-sol" }, + { + "path": "../sdk-coin-starknet" + }, { "path": "../sdk-coin-stx" }, diff --git a/modules/sdk-coin-starknet/.eslintignore b/modules/sdk-coin-starknet/.eslintignore new file mode 100644 index 0000000000..1586a150fa --- /dev/null +++ b/modules/sdk-coin-starknet/.eslintignore @@ -0,0 +1,4 @@ +node_modules +.idea +public +dist diff --git a/modules/sdk-coin-starknet/.gitignore b/modules/sdk-coin-starknet/.gitignore new file mode 100644 index 0000000000..67ccce4c64 --- /dev/null +++ b/modules/sdk-coin-starknet/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.idea/ +dist/ diff --git a/modules/sdk-coin-starknet/.mocharc.yml b/modules/sdk-coin-starknet/.mocharc.yml new file mode 100644 index 0000000000..f499ec0a83 --- /dev/null +++ b/modules/sdk-coin-starknet/.mocharc.yml @@ -0,0 +1,8 @@ +require: 'tsx' +timeout: '60000' +reporter: 'min' +reporter-option: + - 'cdn=true' + - 'json=false' +exit: true +spec: ['test/unit/**/*.ts'] diff --git a/modules/sdk-coin-starknet/.npmignore b/modules/sdk-coin-starknet/.npmignore new file mode 100644 index 0000000000..d5fb3a098c --- /dev/null +++ b/modules/sdk-coin-starknet/.npmignore @@ -0,0 +1,14 @@ +!dist/ +dist/test/ +dist/tsconfig.tsbuildinfo +.idea/ +.prettierrc.yml +tsconfig.json +src/ +test/ +scripts/ +.nyc_output +CODEOWNERS +node_modules/ +.prettierignore +.mocharc.js diff --git a/modules/sdk-coin-starknet/.prettierignore b/modules/sdk-coin-starknet/.prettierignore new file mode 100644 index 0000000000..3a11d6af29 --- /dev/null +++ b/modules/sdk-coin-starknet/.prettierignore @@ -0,0 +1,2 @@ +.nyc_output/ +dist/ diff --git a/modules/sdk-coin-starknet/.prettierrc.yml b/modules/sdk-coin-starknet/.prettierrc.yml new file mode 100644 index 0000000000..7c3d8dd32a --- /dev/null +++ b/modules/sdk-coin-starknet/.prettierrc.yml @@ -0,0 +1,3 @@ +printWidth: 120 +singleQuote: true +trailingComma: 'es5' diff --git a/modules/sdk-coin-starknet/README.md b/modules/sdk-coin-starknet/README.md new file mode 100644 index 0000000000..d228ff7e11 --- /dev/null +++ b/modules/sdk-coin-starknet/README.md @@ -0,0 +1,32 @@ +# BitGo sdk-coin-starknet + +BitGo SDK coin library for [Starknet](https://www.starknet.io/) — a ZK-rollup L2 secured by Ethereum. + +Native Starknet accounts at BitGo use OpenZeppelin's `EthAccountUpgradeable` contract, which validates secp256k1 ECDSA signatures on-chain via Cairo's `secp256k1_get_point_from_x_syscall`. This lets BitGo reuse its existing 2-of-3 ECDSA TSS (the same protocol used for Bitcoin, Ethereum, ICP) with no new cryptographic work. + +## Installation + +All coins are loaded traditionally through the `bitgo` package. If you are using coins individually, you will be accessing the coin via the `@bitgo/sdk-api` package. + +In your project install both `@bitgo/sdk-api` and `@bitgo/sdk-coin-starknet`. + +```shell +npm i @bitgo/sdk-api @bitgo/sdk-coin-starknet +``` + +Next, you will be able to initialize an instance of "bitgo" through `@bitgo/sdk-api` instead of `bitgo`. + +```javascript +import { BitGoAPI } from '@bitgo/sdk-api'; +import { Starknet } from '@bitgo/sdk-coin-starknet'; + +const sdk = new BitGoAPI(); + +sdk.register('starknet', Starknet.createInstance); +``` + +## Development + +Most of the coin implementations are derived from `@bitgo/sdk-core`, `@bitgo/statics`, and coin specific packages. These implementations are used to interact with the BitGo API and BitGo platform services. + +This package currently provides only the coin-class scaffold. Address derivation, transaction building, signing, and RPC client are tracked in follow-up tickets. diff --git a/modules/sdk-coin-starknet/package.json b/modules/sdk-coin-starknet/package.json new file mode 100644 index 0000000000..bf7b0fc426 --- /dev/null +++ b/modules/sdk-coin-starknet/package.json @@ -0,0 +1,51 @@ +{ + "name": "@bitgo/sdk-coin-starknet", + "version": "1.0.0", + "description": "BitGo SDK coin library for Starknet", + "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 .", + "prepare": "npm run build", + "test": "npm run coverage", + "coverage": "nyc -- npm run unit-test", + "unit-test": "mocha" + }, + "author": "BitGo SDK Team ", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "repository": { + "type": "git", + "url": "https://github.com/BitGo/BitGoJS.git", + "directory": "modules/sdk-coin-starknet" + }, + "lint-staged": { + "*.{js,ts}": [ + "yarn prettier --write", + "yarn eslint --fix" + ] + }, + "publishConfig": { + "access": "public" + }, + "nyc": { + "extension": [ + ".ts" + ] + }, + "dependencies": { + "@bitgo/sdk-core": "^36.44.0", + "@bitgo/statics": "^58.39.0" + }, + "devDependencies": { + "@bitgo/sdk-api": "^1.79.2", + "@bitgo/sdk-lib-mpc": "^10.12.0", + "@bitgo/sdk-test": "^9.1.42" + } +} diff --git a/modules/sdk-coin-starknet/src/index.ts b/modules/sdk-coin-starknet/src/index.ts new file mode 100644 index 0000000000..4e982b29e1 --- /dev/null +++ b/modules/sdk-coin-starknet/src/index.ts @@ -0,0 +1,3 @@ +export * from './register'; +export * from './starknet'; +export * from './tstarknet'; diff --git a/modules/sdk-coin-starknet/src/register.ts b/modules/sdk-coin-starknet/src/register.ts new file mode 100644 index 0000000000..0604e15a66 --- /dev/null +++ b/modules/sdk-coin-starknet/src/register.ts @@ -0,0 +1,8 @@ +import { BitGoBase } from '@bitgo/sdk-core'; +import { Starknet } from './starknet'; +import { Tstarknet } from './tstarknet'; + +export const register = (sdk: BitGoBase): void => { + sdk.register('starknet', Starknet.createInstance); + sdk.register('tstarknet', Tstarknet.createInstance); +}; diff --git a/modules/sdk-coin-starknet/src/starknet.ts b/modules/sdk-coin-starknet/src/starknet.ts new file mode 100644 index 0000000000..215946dff7 --- /dev/null +++ b/modules/sdk-coin-starknet/src/starknet.ts @@ -0,0 +1,113 @@ +import { + AuditDecryptedKeyParams, + BaseCoin, + BitGoBase, + KeyPair, + MPCAlgorithm, + MultisigType, + multisigTypes, + ParsedTransaction, + ParseTransactionOptions, + SignedTransaction, + SignTransactionOptions, + VerifyAddressOptions, + VerifyTransactionOptions, +} from '@bitgo/sdk-core'; +import { auditEcdsaPrivateKey } from '@bitgo/sdk-lib-mpc'; +import { BaseCoin as StaticsBaseCoin } from '@bitgo/statics'; + +export class Starknet extends BaseCoin { + protected readonly _staticsCoin: Readonly; + + protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { + super(bitgo); + + if (!staticsCoin) { + throw new Error('missing required constructor parameter staticsCoin'); + } + + this._staticsCoin = staticsCoin; + } + + static createInstance(bitgo: BitGoBase, staticsCoin?: Readonly): BaseCoin { + return new Starknet(bitgo, staticsCoin); + } + + /** @inheritDoc */ + public getBaseFactor(): number { + return Math.pow(10, this._staticsCoin.decimalPlaces); + } + + /** @inheritDoc */ + public getChain(): string { + return this._staticsCoin.name; + } + + /** @inheritDoc */ + public getFamily(): string { + return this._staticsCoin.family; + } + + /** @inheritDoc */ + public getFullName(): string { + return this._staticsCoin.fullName; + } + + /** @inheritDoc */ + supportsTss(): boolean { + return true; + } + + /** @inheritDoc */ + getDefaultMultisigType(): MultisigType { + return multisigTypes.tss; + } + + /** @inheritDoc */ + getMPCAlgorithm(): MPCAlgorithm { + return 'ecdsa'; + } + + /** @inheritDoc */ + verifyTransaction(params: VerifyTransactionOptions): Promise { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + isWalletAddress(params: VerifyAddressOptions): Promise { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + parseTransaction(params: ParseTransactionOptions): Promise { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + generateKeyPair(seed?: Buffer): KeyPair { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + isValidPub(pub: string): boolean { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + isValidAddress(address: string): boolean { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + signTransaction(params: SignTransactionOptions): Promise { + throw new Error('Method not implemented.'); + } + + /** @inheritDoc */ + auditDecryptedKey({ multiSigType, prv, publicKey }: AuditDecryptedKeyParams): void { + if (multiSigType !== 'tss') { + throw new Error('Unsupported multiSigType'); + } + auditEcdsaPrivateKey(prv, publicKey ?? ''); + } +} diff --git a/modules/sdk-coin-starknet/src/tstarknet.ts b/modules/sdk-coin-starknet/src/tstarknet.ts new file mode 100644 index 0000000000..42ea2abe91 --- /dev/null +++ b/modules/sdk-coin-starknet/src/tstarknet.ts @@ -0,0 +1,25 @@ +/** + * Testnet Starknet + * + * @format + */ +import { BaseCoin, BitGoBase } from '@bitgo/sdk-core'; +import { BaseCoin as StaticsBaseCoin } from '@bitgo/statics'; +import { Starknet } from './starknet'; + +export class Tstarknet extends Starknet { + protected readonly _staticsCoin: Readonly; + protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { + super(bitgo, staticsCoin); + + if (!staticsCoin) { + throw new Error('missing required constructor parameter staticsCoin'); + } + + this._staticsCoin = staticsCoin; + } + + static createInstance(bitgo: BitGoBase, staticsCoin?: Readonly): BaseCoin { + return new Tstarknet(bitgo, staticsCoin); + } +} diff --git a/modules/sdk-coin-starknet/test/integration/index.ts b/modules/sdk-coin-starknet/test/integration/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/sdk-coin-starknet/test/unit/index.ts b/modules/sdk-coin-starknet/test/unit/index.ts new file mode 100644 index 0000000000..b932a3b282 --- /dev/null +++ b/modules/sdk-coin-starknet/test/unit/index.ts @@ -0,0 +1,35 @@ +import 'should'; +import { BitGoAPI } from '@bitgo/sdk-api'; +import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test'; +import { Starknet, Tstarknet } from '../../src'; + +describe('Starknet:', function () { + let bitgo: TestBitGoAPI; + + before(function () { + bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' }); + bitgo.safeRegister('starknet', Starknet.createInstance); + bitgo.safeRegister('tstarknet', Tstarknet.createInstance); + bitgo.initializeTestVars(); + }); + + it('should retrieve the mainnet coin', function () { + const coin = bitgo.coin('starknet'); + coin.getChain().should.equal('starknet'); + coin.getFamily().should.equal('starknet'); + coin.getFullName().should.equal('Starknet'); + coin.getBaseFactor().should.equal(1e18); + coin.supportsTss().should.equal(true); + coin.getMPCAlgorithm().should.equal('ecdsa'); + }); + + it('should retrieve the testnet coin', function () { + const coin = bitgo.coin('tstarknet'); + coin.getChain().should.equal('tstarknet'); + coin.getFamily().should.equal('starknet'); + coin.getFullName().should.equal('Testnet Starknet'); + coin.getBaseFactor().should.equal(1e18); + coin.supportsTss().should.equal(true); + coin.getMPCAlgorithm().should.equal('ecdsa'); + }); +}); diff --git a/modules/sdk-coin-starknet/tsconfig.json b/modules/sdk-coin-starknet/tsconfig.json new file mode 100644 index 0000000000..64aeea134a --- /dev/null +++ b/modules/sdk-coin-starknet/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./", + "strictPropertyInitialization": false, + "esModuleInterop": true, + "typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"] + }, + "include": ["src/**/*", "test/**/*"], + "exclude": ["node_modules"], + "references": [ + { + "path": "../sdk-api" + }, + { + "path": "../sdk-core" + }, + { + "path": "../statics" + }, + { + "path": "../sdk-test" + } + ] +} diff --git a/modules/sdk-core/src/bitgo/environments.ts b/modules/sdk-core/src/bitgo/environments.ts index 905a6e44a0..fdd201ab35 100644 --- a/modules/sdk-core/src/bitgo/environments.ts +++ b/modules/sdk-core/src/bitgo/environments.ts @@ -77,6 +77,7 @@ interface EnvironmentTemplate { sgbExplorerBaseUrl?: string; sgbExplorerApiToken?: string; icpNodeUrl: string; + starknetNodeUrl: string; kaspaNodeUrl: string; hyperLiquidNodeUrl: string; wemixExplorerBaseUrl?: string; @@ -365,6 +366,7 @@ const mainnetBase: EnvironmentTemplate = { }, }, icpNodeUrl: 'https://ic0.app', + starknetNodeUrl: 'https://starknet-mainnet.public.blastapi.io/rpc/v0_8', kaspaNodeUrl: 'https://api.kaspa.org', hyperLiquidNodeUrl: 'https://api.hyperliquid.xyz', worldExplorerBaseUrl: 'https://worldscan.org/', @@ -444,6 +446,7 @@ const testnetBase: EnvironmentTemplate = { xdcExplorerBaseUrl: 'https://api.etherscan.io/v2', sgbExplorerBaseUrl: 'https://coston-explorer.flare.network', icpNodeUrl: 'https://ic0.app', + starknetNodeUrl: 'https://starknet-sepolia.public.blastapi.io/rpc/v0_8', kaspaNodeUrl: 'https://api-tn10.kaspa.org', hyperLiquidNodeUrl: 'https://api.hyperliquid-testnet.xyz', monExplorerBaseUrl: 'https://api.etherscan.io/v2', diff --git a/modules/statics/src/allCoinsAndTokens.ts b/modules/statics/src/allCoinsAndTokens.ts index a9a3612922..63d1c10367 100644 --- a/modules/statics/src/allCoinsAndTokens.ts +++ b/modules/statics/src/allCoinsAndTokens.ts @@ -120,6 +120,7 @@ import { SGB_FEATURES, SOL_FEATURES, SONEIUM_FEATURES, + STARKNET_FEATURES, STX_FEATURES, SUI_FEATURES, SUI_TOKEN_FEATURES, @@ -2274,6 +2275,28 @@ export const allCoinsAndTokens = [ POLYX_FEATURES, KeyCurve.Ed25519 ), + account( + 'ccd6eb4a-4a05-44f0-8b44-290804ee72d3', + 'starknet', + 'Starknet', + Networks.main.starknet, + 18, + UnderlyingAsset.STARKNET, + BaseUnit.STARKNET, + STARKNET_FEATURES, + KeyCurve.Secp256k1 + ), + account( + 'f1fca130-a151-4663-b675-ce413ae519cd', + 'tstarknet', + 'Testnet Starknet', + Networks.test.starknet, + 18, + UnderlyingAsset.STARKNET, + BaseUnit.STARKNET, + STARKNET_FEATURES, + KeyCurve.Secp256k1 + ), account( 'cf601b71-5ed5-4524-b545-d6d19051781f', 'flow', diff --git a/modules/statics/src/base.ts b/modules/statics/src/base.ts index 00e8e8611b..f86d2a293d 100644 --- a/modules/statics/src/base.ts +++ b/modules/statics/src/base.ts @@ -115,6 +115,7 @@ export enum CoinFamily { SOL = 'sol', SONIC = 'sonic', SONEIUM = 'soneium', + STARKNET = 'starknet', STT = 'stt', SUI = 'sui', STX = 'stx', @@ -672,6 +673,7 @@ export enum UnderlyingAsset { SOMI = 'somi', // Somnia Chain SONEIUM = 'soneium', SONIC = 'sonic', + STARKNET = 'starknet', // Starknet L2 native asset (distinct from STRK, the L1 ERC-20) STT = 'stt', STX = 'stx', SUI = 'sui', @@ -3902,6 +3904,7 @@ export enum BaseUnit { DOT = 'planck', XRP = 'drop', XTZ = 'micro xtz', + STARKNET = 'fri', STX = 'micro-STX', SUI = 'MIST', TON = 'nanoton', diff --git a/modules/statics/src/coinFeatures.ts b/modules/statics/src/coinFeatures.ts index c65d1b2c6e..e7dbd43af0 100644 --- a/modules/statics/src/coinFeatures.ts +++ b/modules/statics/src/coinFeatures.ts @@ -645,6 +645,15 @@ export const ICP_FEATURES = [ CoinFeature.REBUILD_ON_CUSTODY_SIGNING, ]; +export const STARKNET_FEATURES = [ + ...ACCOUNT_COIN_DEFAULT_FEATURES, + CoinFeature.TSS, + CoinFeature.TSS_COLD, + CoinFeature.MPCV2, + CoinFeature.SUPPORTS_TOKENS, + CoinFeature.REBUILD_ON_CUSTODY_SIGNING, +]; + export const TAO_FEATURES = [ ...ACCOUNT_COIN_DEFAULT_FEATURES, CoinFeature.TSS, diff --git a/modules/statics/src/networks.ts b/modules/statics/src/networks.ts index 3d0f1ae216..410c52bff2 100644 --- a/modules/statics/src/networks.ts +++ b/modules/statics/src/networks.ts @@ -942,6 +942,20 @@ class SolTestnet extends Testnet implements AccountNetwork { explorerUrl = 'https://explorer.solana.com/tx/?cluster=devnet'; } +class Starknet extends Mainnet implements AccountNetwork { + name = 'Starknet'; + family = CoinFamily.STARKNET; + explorerUrl = 'https://voyager.online/tx/'; + accountExplorerUrl = 'https://voyager.online/contract/'; +} + +class StarknetTestnet extends Testnet implements AccountNetwork { + name = 'Testnet Starknet'; + family = CoinFamily.STARKNET; + explorerUrl = 'https://sepolia.voyager.online/tx/'; + accountExplorerUrl = 'https://sepolia.voyager.online/contract/'; +} + class Sui extends Mainnet implements AccountNetwork { name = 'Sui'; family = CoinFamily.SUI; @@ -2854,6 +2868,7 @@ export const Networks = { sgb: Object.freeze(new Songbird()), sol: Object.freeze(new Sol()), sonic: Object.freeze(new Sonic()), + starknet: Object.freeze(new Starknet()), sui: Object.freeze(new Sui()), near: Object.freeze(new Near()), stx: Object.freeze(new Stx()), @@ -2982,6 +2997,7 @@ export const Networks = { sei: Object.freeze(new SeiTestnet()), seievm: Object.freeze(new SeiEvmTestnet()), sol: Object.freeze(new SolTestnet()), + starknet: Object.freeze(new StarknetTestnet()), sui: Object.freeze(new SuiTestnet()), near: Object.freeze(new NearTestnet()), stx: Object.freeze(new StxTestnet()), diff --git a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts index 16419862e3..f66c96733e 100644 --- a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts +++ b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts @@ -136,6 +136,7 @@ export const expectedColdFeatures = { 'sol', 'sonic', 'somi', + 'starknet', 'sui', 'unieth', 'usdt0', @@ -220,6 +221,7 @@ export const expectedColdFeatures = { 'tsei', 'tsgb', 'tsol', + 'tstarknet', 'tstt', 'tsui', 'ttao', diff --git a/tsconfig.packages.json b/tsconfig.packages.json index 7e4d5d74c7..8145df7655 100644 --- a/tsconfig.packages.json +++ b/tsconfig.packages.json @@ -220,6 +220,9 @@ { "path": "./modules/sdk-coin-soneium" }, + { + "path": "./modules/sdk-coin-starknet" + }, { "path": "./modules/sdk-coin-stt" },