diff --git a/.changeset/honest-pigs-rhyme.md b/.changeset/honest-pigs-rhyme.md new file mode 100644 index 0000000..5875912 --- /dev/null +++ b/.changeset/honest-pigs-rhyme.md @@ -0,0 +1,9 @@ +--- +'@rosen-chains/abstract-chain': major +--- + +- add abstract NATIVE_TOKEN_ID variable +- add RosenTokens to constructor arguments +- consider decimals drop + - every function of `AbstractChain` and `AbstractUtxoChain` gets and returns the wrapped values + - network functions (functions of `AbstractChainNetwork` and `AbstractUtxoChainNetwork`) should still return **the actual values** diff --git a/package-lock.json b/package-lock.json index 51ea20a..a1a3cfc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4887,8 +4887,9 @@ } }, "node_modules/@rosen-bridge/minimum-fee": { - "version": "2.0.0", - "license": "GPL-3.0", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rosen-bridge/minimum-fee/-/minimum-fee-2.1.0.tgz", + "integrity": "sha512-vd7+f4I//u4PaN5PRkwMtSfWCk4X7GoAwfD+qxwiVtpDvvE655eqxGY2z6VGWjuKlIqC8EUNRumy23t/tnhQ2w==", "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", @@ -4901,15 +4902,16 @@ } }, "node_modules/@rosen-bridge/rosen-extractor": { - "version": "5.0.1", - "license": "GPL-3.0", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rosen-bridge/rosen-extractor/-/rosen-extractor-6.0.0.tgz", + "integrity": "sha512-86xyyfycqIk/ViuYnUIDhnaxnl4VAYby4fP11HpkANAfMGQHXwXPvLqMQLJtzlDWKNCXOqK0nagnlZhZhBtfYA==", "dependencies": { "@blockfrost/blockfrost-js": "^5.4.0", "@cardano-ogmios/schema": "^6.0.3", "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/address-codec": "^0.2.1", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/tokens": "^1.0.0", + "@rosen-bridge/tokens": "^1.2.0", "bitcoinjs-lib": "^6.1.5", "ergo-lib-wasm-nodejs": "^0.24.1", "ethers": "^6.11.1", @@ -4949,8 +4951,9 @@ } }, "node_modules/@rosen-bridge/tokens": { - "version": "1.1.0", - "license": "GPL-3.0" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rosen-bridge/tokens/-/tokens-1.2.0.tgz", + "integrity": "sha512-11IL+FtywP7As8FBNcwdaiyTNTmREaWUHb6MxOOa7pjSAXsgyYjgVhtCuPJKLkpzN0qYXDjjZkAuDHkqhnH6Rg==" }, "node_modules/@rosen-chains/abstract-chain": { "resolved": "packages/abstract-chain", @@ -16567,8 +16570,9 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/minimum-fee": "^2.0.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", + "@rosen-bridge/minimum-fee": "^2.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "blakejs": "^1.2.1" }, "devDependencies": { @@ -16595,8 +16599,8 @@ "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/bitcoin-utxo-selection": "^0.2.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "bitcoinjs-lib": "^6.1.5" }, "devDependencies": { @@ -17338,8 +17342,8 @@ "@emurgo/cardano-serialization-lib-nodejs": "^11.3.1", "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "bech32": "^2.0.0" }, "devDependencies": { @@ -17369,8 +17373,8 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "ergo-lib-wasm-nodejs": "^0.24.1" }, "devDependencies": { @@ -17399,7 +17403,8 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "ethers": "^6.11.1" }, "devDependencies": { diff --git a/packages/abstract-chain/lib/AbstractChain.ts b/packages/abstract-chain/lib/AbstractChain.ts index bdee001..b4aba39 100644 --- a/packages/abstract-chain/lib/AbstractChain.ts +++ b/packages/abstract-chain/lib/AbstractChain.ts @@ -1,6 +1,7 @@ import { AbstractLogger, DummyLogger } from '@rosen-bridge/abstract-logger'; import { ChainMinimumFee } from '@rosen-bridge/minimum-fee'; import { AbstractRosenDataExtractor } from '@rosen-bridge/rosen-extractor'; +import { RosenTokens, TokenMap } from '@rosen-bridge/tokens'; import { blake2b } from 'blakejs'; import ChainUtils from './ChainUtils'; import { @@ -27,19 +28,23 @@ import { import PaymentTransaction from './PaymentTransaction'; abstract class AbstractChain { - protected abstract CHAIN: string; + abstract readonly CHAIN: string; + abstract readonly NATIVE_TOKEN_ID: string; protected abstract extractor: AbstractRosenDataExtractor | undefined; protected network: AbstractChainNetwork; protected configs: ChainConfigs; + protected tokenMap: TokenMap; logger: AbstractLogger; constructor( network: AbstractChainNetwork, configs: ChainConfigs, + tokens: RosenTokens, logger?: AbstractLogger ) { this.network = network; this.configs = configs; + this.tokenMap = new TokenMap(tokens); this.logger = logger ? logger : new DummyLogger(); } @@ -345,7 +350,20 @@ abstract class AbstractChain { this.logger.debug(`returning empty assets for address [${address}]`); return { nativeToken: 0n, tokens: [] }; } - return await this.network.getAddressAssets(address); + const rawBalance = await this.network.getAddressAssets(address); + const wrappedNativeToken = this.tokenMap.wrapAmount( + this.NATIVE_TOKEN_ID, + rawBalance.nativeToken, + this.CHAIN + ).amount; + const wrappedAssets = rawBalance.tokens.map((token) => ({ + id: token.id, + value: this.tokenMap.wrapAmount(token.id, token.value, this.CHAIN).amount, + })); + return { + nativeToken: wrappedNativeToken, + tokens: wrappedAssets, + }; }; /** diff --git a/packages/abstract-chain/package.json b/packages/abstract-chain/package.json index 1b72961..85805e3 100644 --- a/packages/abstract-chain/package.json +++ b/packages/abstract-chain/package.json @@ -22,8 +22,9 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/minimum-fee": "^2.0.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", + "@rosen-bridge/minimum-fee": "^2.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "blakejs": "^1.2.1" }, "devDependencies": { diff --git a/packages/abstract-chain/tests/AbstractChain.spec.ts b/packages/abstract-chain/tests/AbstractChain.spec.ts index 2c79aa3..0ab51af 100644 --- a/packages/abstract-chain/tests/AbstractChain.spec.ts +++ b/packages/abstract-chain/tests/AbstractChain.spec.ts @@ -763,7 +763,7 @@ describe('AbstractChain', () => { const network = new TestChainNetwork(); /** - * @target ErgoChain.getTxConfirmationStatus should return + * @target AbstractChain.getTxConfirmationStatus should return * ConfirmedEnough when tx confirmation is more than required number * @dependencies * @scenario @@ -789,7 +789,7 @@ describe('AbstractChain', () => { }); /** - * @target ErgoChain.getTxConfirmationStatus should return + * @target AbstractChain.getTxConfirmationStatus should return * NotConfirmedEnough when payment tx confirmation is less than required number * @dependencies * @scenario @@ -816,7 +816,7 @@ describe('AbstractChain', () => { }); /** - * @target ErgoChain.getTxConfirmationStatus should return + * @target AbstractChain.getTxConfirmationStatus should return * NotFound when tx confirmation is -1 * @dependencies * @scenario @@ -840,6 +840,33 @@ describe('AbstractChain', () => { }); }); + describe('getAddressAssets', () => { + const network = new TestChainNetwork(); + + /** + * @target AbstractChain.getAddressAssets should return wrapped values + * @dependencies + * @scenario + * - mock a network object to return actual values for the assets + * - run test + * - check returned value + * @expected + * - it should return the wrapped values + */ + it('should return wrapped values', async () => { + // mock a network object to return actual values for the assets + const getAddressAssetsSpy = spyOn(network, 'getAddressAssets'); + getAddressAssetsSpy.mockResolvedValueOnce(testData.actualBalance); + + // run test + const chain = generateChainObject(network); + const result = await chain.getAddressAssets('address'); + + // check returned value + expect(result).toEqual(testData.wrappedBalance); + }); + }); + describe('hasLockAddressEnoughAssets', () => { const requiredAssets = { nativeToken: 100n, diff --git a/packages/abstract-chain/tests/AbstractUtxoChain.spec.ts b/packages/abstract-chain/tests/AbstractUtxoChain.spec.ts index e36b6fe..dd29d4f 100644 --- a/packages/abstract-chain/tests/AbstractUtxoChain.spec.ts +++ b/packages/abstract-chain/tests/AbstractUtxoChain.spec.ts @@ -1,31 +1,11 @@ -import TestUtxoChain from './TestUtxoChain'; -import TestUtxoChainNetwork from './network/TestUtxoChainNetwork'; -import { AssetBalance, ChainConfigs } from '../lib'; import { when } from 'jest-when'; +import TestUtxoChainNetwork from './network/TestUtxoChainNetwork'; +import { AssetBalance } from '../lib'; +import { generateUtxoChainObject } from './testUtils'; const spyOn = jest.spyOn; describe('AbstractUtxoChain', () => { - const generateChainObject = (network: TestUtxoChainNetwork) => { - const config: ChainConfigs = { - fee: 100n, - confirmations: { - observation: 5, - payment: 6, - cold: 7, - manual: 8, - }, - addresses: { - lock: 'lock_addr', - cold: 'cold_addr', - permit: 'permit_addr', - fraud: 'fraud_addr', - }, - rwtId: 'rwt', - }; - return new TestUtxoChain(network, config); - }; - describe('getCoveringBoxes', () => { const emptyMap = new Map(); @@ -50,7 +30,7 @@ describe('AbstractUtxoChain', () => { .mockResolvedValueOnce(['serialized-box-1', 'serialized-box-2']); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -111,7 +91,7 @@ describe('AbstractUtxoChain', () => { .mockResolvedValueOnce(['serialized-box-1', 'serialized-box-2']); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -174,7 +154,7 @@ describe('AbstractUtxoChain', () => { // Mock chain 'getBoxInfo' function to return mocked boxes assets // (second box doesn't contain required token) - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -240,7 +220,7 @@ describe('AbstractUtxoChain', () => { .mockResolvedValueOnce(['serialized-box-11', 'serialized-box-12']); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); Array.from({ length: 12 }, (x, i) => i).map((i) => { when(getBoxInfoSpy) @@ -303,7 +283,7 @@ describe('AbstractUtxoChain', () => { .mockResolvedValueOnce(['serialized-box-11', 'serialized-box-12']); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); Array.from({ length: 12 }, (x, i) => i).map((i) => { when(getBoxInfoSpy) @@ -361,7 +341,7 @@ describe('AbstractUtxoChain', () => { }; // Run test - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const result = await chain.getCoveringBoxes( '', requiredAssets, @@ -400,7 +380,7 @@ describe('AbstractUtxoChain', () => { trackMap.set('box1', 'serialized-tracked-box-1'); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -475,7 +455,7 @@ describe('AbstractUtxoChain', () => { trackMap.set('box1', 'serialized-tracked-box-1'); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -552,7 +532,7 @@ describe('AbstractUtxoChain', () => { const forbiddenIds = ['box1']; // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -618,7 +598,7 @@ describe('AbstractUtxoChain', () => { trackMap.set('box1', undefined); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') @@ -676,7 +656,7 @@ describe('AbstractUtxoChain', () => { trackMap.set('box2', 'serialized-tracked-box-1'); // Mock chain 'getBoxInfo' function to return mocked boxes assets - const chain = generateChainObject(network); + const chain = generateUtxoChainObject(network); const getBoxInfoSpy = spyOn(chain, 'getBoxInfo'); when(getBoxInfoSpy) .calledWith('serialized-box-1') diff --git a/packages/abstract-chain/tests/TestChain.ts b/packages/abstract-chain/tests/TestChain.ts index 5cd4913..0758fbb 100644 --- a/packages/abstract-chain/tests/TestChain.ts +++ b/packages/abstract-chain/tests/TestChain.ts @@ -5,10 +5,11 @@ import { TransactionAssetBalance, TransactionType, } from '../lib'; -import TestRosenDataExtractor from './TestRosenDataExtractor'; +import TestRosenDataExtractor from './extractor/TestRosenDataExtractor'; class TestChain extends AbstractChain { - protected CHAIN = 'test'; + NATIVE_TOKEN_ID = 'test-native-token'; + CHAIN = 'test'; protected extractor = new TestRosenDataExtractor(); notImplemented = () => { diff --git a/packages/abstract-chain/tests/TestRosenDataExtractor.ts b/packages/abstract-chain/tests/TestRosenDataExtractor.ts deleted file mode 100644 index 894e62f..0000000 --- a/packages/abstract-chain/tests/TestRosenDataExtractor.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - AbstractRosenDataExtractor, - RosenData, -} from '@rosen-bridge/rosen-extractor'; - -class TestRosenDataExtractor extends AbstractRosenDataExtractor { - constructor() { - super('', { idKeys: {}, tokens: [] }); - } - - get = (tx: string): RosenData | undefined => { - throw Error(`not mocked`); - }; -} - -export default TestRosenDataExtractor; diff --git a/packages/abstract-chain/tests/TestUtxoChain.ts b/packages/abstract-chain/tests/TestUtxoChain.ts index a0326e1..78bcaa1 100644 --- a/packages/abstract-chain/tests/TestUtxoChain.ts +++ b/packages/abstract-chain/tests/TestUtxoChain.ts @@ -1,8 +1,9 @@ import { AbstractUtxoChain, BoxInfo } from '../lib'; -import TestRosenDataExtractor from './TestRosenDataExtractor'; +import TestRosenDataExtractor from './extractor/TestRosenDataExtractor'; class TestUtxoChain extends AbstractUtxoChain { - protected CHAIN = 'test-utxo'; + NATIVE_TOKEN_ID = 'test-utxo-native-token'; + CHAIN = 'test-utxo'; protected extractor = new TestRosenDataExtractor(); notImplemented = () => { diff --git a/packages/abstract-chain/tests/extractor/TestRosenDataExtractor.ts b/packages/abstract-chain/tests/extractor/TestRosenDataExtractor.ts index a00bb67..3acbfb0 100644 --- a/packages/abstract-chain/tests/extractor/TestRosenDataExtractor.ts +++ b/packages/abstract-chain/tests/extractor/TestRosenDataExtractor.ts @@ -3,8 +3,15 @@ import { RosenData, } from '@rosen-bridge/rosen-extractor'; -export class TestRosenDataExtractor extends AbstractRosenDataExtractor { - get = (transaction: string): RosenData | undefined => { +class TestRosenDataExtractor extends AbstractRosenDataExtractor { + readonly chain = 'test'; + constructor() { + super('', { idKeys: {}, tokens: [] }); + } + + extractRawData = (tx: string): RosenData | undefined => { throw Error(`not mocked`); }; } + +export default TestRosenDataExtractor; diff --git a/packages/abstract-chain/tests/network/TestChainNetwork.ts b/packages/abstract-chain/tests/network/TestChainNetwork.ts index 535abe4..27a82ec 100644 --- a/packages/abstract-chain/tests/network/TestChainNetwork.ts +++ b/packages/abstract-chain/tests/network/TestChainNetwork.ts @@ -1,5 +1,5 @@ -import { AbstractChainNetwork, BlockInfo } from '../../lib'; -import TestRosenDataExtractor from '../TestRosenDataExtractor'; +import { AbstractChainNetwork, AssetBalance, BlockInfo } from '../../lib'; +import TestRosenDataExtractor from '../extractor/TestRosenDataExtractor'; class TestUtxoChainNetwork extends AbstractChainNetwork { extractor = new TestRosenDataExtractor(); @@ -9,11 +9,13 @@ class TestUtxoChainNetwork extends AbstractChainNetwork { }; getHeight = this.notImplemented; - getAddressAssets = this.notImplemented; submitTransaction = this.notImplemented; getMempoolTransactions = this.notImplemented; getTokenDetail = this.notImplemented; + getAddressAssets = (address: string): Promise => { + throw Error('Not mocked'); + }; getBlockTransactionIds = (blockId: string): Promise> => { throw Error('Not mocked'); }; diff --git a/packages/abstract-chain/tests/network/TestUtxoChainNetwork.ts b/packages/abstract-chain/tests/network/TestUtxoChainNetwork.ts index 5016bf7..9052619 100644 --- a/packages/abstract-chain/tests/network/TestUtxoChainNetwork.ts +++ b/packages/abstract-chain/tests/network/TestUtxoChainNetwork.ts @@ -1,5 +1,5 @@ import { AbstractUtxoChainNetwork } from '../../lib'; -import TestRosenDataExtractor from '../TestRosenDataExtractor'; +import TestRosenDataExtractor from '../extractor/TestRosenDataExtractor'; class TestUtxoChainNetwork extends AbstractUtxoChainNetwork { extractor = new TestRosenDataExtractor(); diff --git a/packages/abstract-chain/tests/testData.ts b/packages/abstract-chain/tests/testData.ts index 017ab39..83c1d03 100644 --- a/packages/abstract-chain/tests/testData.ts +++ b/packages/abstract-chain/tests/testData.ts @@ -1,4 +1,5 @@ -import { EventTrigger } from '../lib'; +import { RosenTokens } from '@rosen-bridge/tokens'; +import { AssetBalance, EventTrigger } from '../lib'; export const paymentTxConfirmation = 6; @@ -61,3 +62,119 @@ export const validEventWithHighFee: EventTrigger = { WIDsHash: 'bb2b2272816e1e9993fc535c0cf57c668f5cd39c67cfcd55b4422b1aa87cd0c3', WIDsCount: 2, }; + +export const testTokenMap: RosenTokens = { + idKeys: { + test: 'tokenId', + 'test-utxo': 'tokenId', + }, + tokens: [ + { + test: { + tokenId: 'test-native-token', + name: 'test-native-token', + decimals: 2, + metaData: { + type: 'native', + residency: 'native', + }, + }, + 'test-utxo': { + tokenId: 'wrapped-native-token', + name: 'wrapped-test-native-token', + decimals: 2, + metaData: { + type: 'ANY', + residency: 'wrapped', + }, + }, + }, + { + test: { + tokenId: 'wrapped-test-utxo-native-token', + name: 'wrapped-test-utxo-native-token', + decimals: 3, + metaData: { + type: 'ANY', + residency: 'wrapped', + }, + }, + 'test-utxo': { + tokenId: 'test-utxo-native-token', + name: 'test-utxo-native-token', + decimals: 3, + metaData: { + type: 'native', + residency: 'native', + }, + }, + }, + { + test: { + tokenId: 'multi-decimal-token1', + name: 'multi-decimal-token1', + decimals: 4, + metaData: { + type: 'ANY', + residency: 'native', + }, + }, + 'test-utxo': { + tokenId: 'wrapped-multi-decimal-token1', + name: 'wrapped-multi-decimal-token1', + decimals: 1, + metaData: { + type: 'ANY', + residency: 'wrapped', + }, + }, + }, + { + test: { + tokenId: 'wrapped-multi-decimal-token2', + name: 'wrapped-multi-decimal-token2', + decimals: 4, + metaData: { + type: 'ANY', + residency: 'wrapped', + }, + }, + 'test-utxo': { + tokenId: 'multi-decimal-token2', + name: 'multi-decimal-token2', + decimals: 0, + metaData: { + type: 'ANY', + residency: 'native', + }, + }, + }, + ], +}; + +export const actualBalance: AssetBalance = { + nativeToken: 10000n, + tokens: [ + { + id: 'multi-decimal-token1', + value: 44123n, + }, + { + id: 'wrapped-multi-decimal-token2', + value: 556600n, + }, + ], +}; +export const wrappedBalance: AssetBalance = { + nativeToken: 10000n, + tokens: [ + { + id: 'multi-decimal-token1', + value: 44n, + }, + { + id: 'wrapped-multi-decimal-token2', + value: 55n, + }, + ], +}; diff --git a/packages/abstract-chain/tests/testUtils.ts b/packages/abstract-chain/tests/testUtils.ts index 227ee7d..30717a3 100644 --- a/packages/abstract-chain/tests/testUtils.ts +++ b/packages/abstract-chain/tests/testUtils.ts @@ -3,6 +3,8 @@ import TestChainNetwork from './network/TestChainNetwork'; import { ChainConfigs } from '../lib'; import TestChain from './TestChain'; import * as testData from './testData'; +import TestUtxoChainNetwork from './network/TestChainNetwork'; +import TestUtxoChain from './TestUtxoChain'; export const generateRandomId = (): string => randomBytes(32).toString('hex'); @@ -23,5 +25,25 @@ export const generateChainObject = (network: TestChainNetwork) => { }, rwtId: 'rwt', }; - return new TestChain(network, config); + return new TestChain(network, config, testData.testTokenMap); +}; + +export const generateUtxoChainObject = (network: TestUtxoChainNetwork) => { + const config: ChainConfigs = { + fee: 100n, + confirmations: { + observation: 5, + payment: 6, + cold: 7, + manual: 8, + }, + addresses: { + lock: 'lock_addr', + cold: 'cold_addr', + permit: 'permit_addr', + fraud: 'fraud_addr', + }, + rwtId: 'rwt', + }; + return new TestUtxoChain(network, config, testData.testTokenMap); }; diff --git a/packages/chains/bitcoin/lib/BitcoinChain.ts b/packages/chains/bitcoin/lib/BitcoinChain.ts index fcdaf54..b5d4643 100644 --- a/packages/chains/bitcoin/lib/BitcoinChain.ts +++ b/packages/chains/bitcoin/lib/BitcoinChain.ts @@ -28,7 +28,7 @@ import Serializer from './Serializer'; import { Psbt, Transaction, address, payments, script } from 'bitcoinjs-lib'; import JsonBigInt from '@rosen-bridge/json-bigint'; import { estimateTxFee, getPsbtTxInputBoxId } from './bitcoinUtils'; -import { BITCOIN_CHAIN, SEGWIT_INPUT_WEIGHT_UNIT } from './constants'; +import { BITCOIN_CHAIN, BTC, SEGWIT_INPUT_WEIGHT_UNIT } from './constants'; import { selectBitcoinUtxos } from '@rosen-bridge/bitcoin-utxo-selection'; import { BitcoinRosenExtractor } from '@rosen-bridge/rosen-extractor'; import { RosenTokens } from '@rosen-bridge/tokens'; @@ -37,6 +37,7 @@ class BitcoinChain extends AbstractUtxoChain { declare network: AbstractBitcoinNetwork; declare configs: BitcoinConfigs; CHAIN = BITCOIN_CHAIN; + NATIVE_TOKEN_ID = BTC; extractor: BitcoinRosenExtractor; protected signFunction: TssSignFunction; protected lockScript: string; @@ -49,7 +50,7 @@ class BitcoinChain extends AbstractUtxoChain { signFunction: TssSignFunction, logger?: AbstractLogger ) { - super(network, configs, logger); + super(network, configs, tokens, logger); this.extractor = new BitcoinRosenExtractor( configs.addresses.lock, tokens, diff --git a/packages/chains/bitcoin/lib/constants.ts b/packages/chains/bitcoin/lib/constants.ts index 27f1a2e..fc689f7 100644 --- a/packages/chains/bitcoin/lib/constants.ts +++ b/packages/chains/bitcoin/lib/constants.ts @@ -1,4 +1,5 @@ export const BITCOIN_CHAIN = 'bitcoin'; +export const BTC = 'btc'; export const SEGWIT_INPUT_WEIGHT_UNIT = 272; export const SEGWIT_OUTPUT_WEIGHT_UNIT = 124; diff --git a/packages/chains/bitcoin/package.json b/packages/chains/bitcoin/package.json index d9d036f..963023d 100644 --- a/packages/chains/bitcoin/package.json +++ b/packages/chains/bitcoin/package.json @@ -36,8 +36,8 @@ "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/bitcoin-utxo-selection": "^0.2.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "bitcoinjs-lib": "^6.1.5" }, "peerDependencies": { diff --git a/packages/chains/cardano/lib/CardanoChain.ts b/packages/chains/cardano/lib/CardanoChain.ts index 92eb0ff..28c88b0 100644 --- a/packages/chains/cardano/lib/CardanoChain.ts +++ b/packages/chains/cardano/lib/CardanoChain.ts @@ -24,7 +24,7 @@ import JSONBigInt from '@rosen-bridge/json-bigint'; import CardanoTransaction from './CardanoTransaction'; import CardanoUtils from './CardanoUtils'; import cardanoUtils from './CardanoUtils'; -import { CARDANO_CHAIN } from './constants'; +import { ADA, CARDANO_CHAIN } from './constants'; import AbstractCardanoNetwork from './network/AbstractCardanoNetwork'; import Serializer from './Serializer'; import { @@ -41,6 +41,7 @@ class CardanoChain extends AbstractUtxoChain { declare network: AbstractCardanoNetwork; declare configs: CardanoConfigs; CHAIN = CARDANO_CHAIN; + NATIVE_TOKEN_ID = ADA; extractor: CardanoRosenExtractor; protected signFunction: (txHash: Uint8Array) => Promise; @@ -51,7 +52,7 @@ class CardanoChain extends AbstractUtxoChain { signFunction: (txHash: Uint8Array) => Promise, logger?: AbstractLogger ) { - super(network, configs, logger); + super(network, configs, tokens, logger); this.extractor = new CardanoRosenExtractor( configs.addresses.lock, tokens, diff --git a/packages/chains/cardano/package.json b/packages/chains/cardano/package.json index ae8afd2..8f17b0c 100644 --- a/packages/chains/cardano/package.json +++ b/packages/chains/cardano/package.json @@ -22,9 +22,9 @@ "dependencies": { "@emurgo/cardano-serialization-lib-nodejs": "^11.3.1", "@rosen-bridge/abstract-logger": "^1.0.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", + "@rosen-bridge/rosen-extractor": "^6.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/tokens": "^1.2.0", "bech32": "^2.0.0" }, "devDependencies": { diff --git a/packages/chains/ergo/lib/ErgoChain.ts b/packages/chains/ergo/lib/ErgoChain.ts index 0fac47e..cf2cc58 100644 --- a/packages/chains/ergo/lib/ErgoChain.ts +++ b/packages/chains/ergo/lib/ErgoChain.ts @@ -16,7 +16,7 @@ import { TransactionType, } from '@rosen-chains/abstract-chain'; import * as wasm from 'ergo-lib-wasm-nodejs'; -import { ERGO_CHAIN, NUMBER_OF_BLOCKS_PER_YEAR } from './constants'; +import { ERG, ERGO_CHAIN, NUMBER_OF_BLOCKS_PER_YEAR } from './constants'; import ErgoTransaction from './ErgoTransaction'; import ErgoUtils from './ErgoUtils'; import AbstractErgoNetwork from './network/AbstractErgoNetwork'; @@ -29,6 +29,7 @@ import { RosenTokens } from '@rosen-bridge/tokens'; class ErgoChain extends AbstractUtxoChain { CHAIN = ERGO_CHAIN; + NATIVE_TOKEN_ID = ERG; extractor: ErgoRosenExtractor; static feeBoxErgoTree = '1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304'; @@ -53,7 +54,7 @@ class ErgoChain extends AbstractUtxoChain { ) => Promise, logger?: AbstractLogger ) { - super(network, configs, logger); + super(network, configs, tokens, logger); this.extractor = new ErgoRosenExtractor( configs.addresses.lock, tokens, diff --git a/packages/chains/ergo/package.json b/packages/chains/ergo/package.json index 9a8b73a..5f1459b 100644 --- a/packages/chains/ergo/package.json +++ b/packages/chains/ergo/package.json @@ -22,8 +22,8 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", - "@rosen-bridge/tokens": "^1.1.0", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "ergo-lib-wasm-nodejs": "^0.24.1" }, "devDependencies": { diff --git a/packages/chains/evm/lib/EvmChain.ts b/packages/chains/evm/lib/EvmChain.ts index 56b8c6f..a1d2f87 100644 --- a/packages/chains/evm/lib/EvmChain.ts +++ b/packages/chains/evm/lib/EvmChain.ts @@ -25,11 +25,11 @@ import { EvmConfigs, TssSignFunction } from './types'; import { Signature, Transaction } from 'ethers'; import Serializer from './Serializer'; import * as EvmUtils from './EvmUtils'; +import { AbstractLogger } from '@rosen-bridge/abstract-logger'; abstract class EvmChain extends AbstractChain { declare network: AbstractEvmNetwork; declare configs: EvmConfigs; - abstract CHAIN: string; abstract CHAIN_ID: bigint; extractor: EvmRosenExtractor | undefined; @@ -38,17 +38,16 @@ abstract class EvmChain extends AbstractChain { constructor( network: AbstractEvmNetwork, - configs: any, + configs: EvmConfigs, tokens: RosenTokens, - nativeToken: string, supportedTokens: Array, signFunction: TssSignFunction, - logger?: any + logger?: AbstractLogger ) { - super(network, configs, logger); + super(network, configs, tokens, logger); this.supportedTokens = supportedTokens; this.signFunction = signFunction; - this.initExtractor(tokens, nativeToken, logger); + this.initExtractor(tokens, logger); } /** @@ -57,16 +56,12 @@ abstract class EvmChain extends AbstractChain { * @param nativeToken * @param logger */ - protected initExtractor = ( - tokens: RosenTokens, - nativeToken: string, - logger?: any - ) => { + protected initExtractor = (tokens: RosenTokens, logger?: any) => { this.extractor = new EvmRosenExtractor( this.configs.addresses.lock, tokens, this.CHAIN, - nativeToken, + this.NATIVE_TOKEN_ID, logger ); }; diff --git a/packages/chains/evm/package.json b/packages/chains/evm/package.json index 7b8122f..e95eb39 100644 --- a/packages/chains/evm/package.json +++ b/packages/chains/evm/package.json @@ -35,7 +35,8 @@ "dependencies": { "@rosen-bridge/abstract-logger": "^1.0.0", "@rosen-bridge/json-bigint": "^0.1.0", - "@rosen-bridge/rosen-extractor": "^5.0.1", + "@rosen-bridge/rosen-extractor": "^6.0.0", + "@rosen-bridge/tokens": "^1.2.0", "ethers": "^6.11.1" }, "peerDependencies": { diff --git a/packages/chains/evm/tests/EvmChain.spec.ts b/packages/chains/evm/tests/EvmChain.spec.ts index 9d67013..564b25b 100644 --- a/packages/chains/evm/tests/EvmChain.spec.ts +++ b/packages/chains/evm/tests/EvmChain.spec.ts @@ -13,32 +13,14 @@ import { TransactionType, } from '@rosen-chains/abstract-chain'; import * as testUtils from './TestUtils'; -import TestChain from './TestChain'; import Serializer from '../lib/Serializer'; import { Transaction, TransactionLike } from 'ethers'; -import { TssSignFunction } from '../lib'; import { mockGetAddressBalanceForNativeToken } from './TestUtils'; describe('EvmChain', () => { const network = new TestEvmNetwork(); - const generateChainObject = ( - network: TestEvmNetwork, - signFn: TssSignFunction = testUtils.mockedSignFn - ) => { - return new TestChain( - network, - testUtils.configs, - { - idKeys: {}, - tokens: [], - }, - 'eth', - TestData.supportedTokens, - signFn - ); - }; - const evmChain = generateChainObject(network); + const evmChain = testUtils.generateChainObject(network); describe('generateMultipleTransactions', () => { /** @@ -1780,7 +1762,7 @@ describe('EvmChain', () => { signatureRecovery: TestData.transaction2SignatureRecovery, }; }; - const evmChain = generateChainObject(network, signFunction); + const evmChain = testUtils.generateChainObject(network, signFunction); // mock PaymentTransaction of unsigned transaction const eventId = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; @@ -1823,7 +1805,7 @@ describe('EvmChain', () => { const signFunction = async (txHash: Uint8Array) => { throw Error(`TestError: sign failed`); }; - const evmChain = generateChainObject(network, signFunction); + const evmChain = testUtils.generateChainObject(network, signFunction); // mock PaymentTransaction of unsigned transaction const eventId = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; diff --git a/packages/chains/evm/tests/TestChain.ts b/packages/chains/evm/tests/TestChain.ts index ec0d232..49af7d2 100644 --- a/packages/chains/evm/tests/TestChain.ts +++ b/packages/chains/evm/tests/TestChain.ts @@ -4,25 +4,17 @@ import { EvmRosenExtractor } from '@rosen-bridge/rosen-extractor'; class TestChain extends EvmChain { CHAIN = 'test'; + NATIVE_TOKEN_ID = 'test-native-token'; CHAIN_ID = 1n; - extractor: EvmRosenExtractor; constructor( network: AbstractEvmNetwork, configs: any, tokens: RosenTokens, - nativeToken: string, supportedTokens: Array, signFunction: TssSignFunction ) { - super(network, configs, tokens, nativeToken, supportedTokens, signFunction); - - this.extractor = new EvmRosenExtractor( - this.configs.addresses.lock, - tokens, - this.CHAIN, - nativeToken - ); + super(network, configs, tokens, supportedTokens, signFunction); } } diff --git a/packages/chains/evm/tests/TestUtils.ts b/packages/chains/evm/tests/TestUtils.ts index 5e75c8c..781f6ad 100644 --- a/packages/chains/evm/tests/TestUtils.ts +++ b/packages/chains/evm/tests/TestUtils.ts @@ -1,8 +1,10 @@ import * as testData from './testData'; -import { EvmConfigs } from '../lib/types'; +import { EvmConfigs, TssSignFunction } from '../lib/types'; import EvmChain from '../lib/EvmChain'; import { vi } from 'vitest'; import { AbstractEvmNetwork } from '../lib'; +import TestEvmNetwork from './network/TestEvmNetwork'; +import TestChain from './TestChain'; const spyOn = vi.spyOn; const observationTxConfirmation = 5; @@ -79,3 +81,16 @@ export const mockGetMaxPriorityFeePerGas = ( ) => { spyOn(network, 'getMaxPriorityFeePerGas').mockResolvedValue(value); }; + +export const generateChainObject = ( + network: TestEvmNetwork, + signFn: TssSignFunction = mockedSignFn +) => { + return new TestChain( + network, + configs, + testData.testTokenMap, + testData.supportedTokens, + signFn + ); +}; diff --git a/packages/chains/evm/tests/testData.ts b/packages/chains/evm/tests/testData.ts index 73b61a3..d27564e 100644 --- a/packages/chains/evm/tests/testData.ts +++ b/packages/chains/evm/tests/testData.ts @@ -3,6 +3,7 @@ import { TransactionType, } from '@rosen-chains/abstract-chain'; import { PaymentOrder, AssetBalance } from '@rosen-chains/abstract-chain'; +import { RosenTokens } from '@rosen-bridge/tokens'; import { Transaction } from 'ethers'; export const lockAddress = '0xedee4752e5a2f595151c94762fb38e5730357785'; @@ -457,3 +458,8 @@ export const transaction2Signature = export const transaction2SignatureRecovery = '01'; export const transaction2TxId = '0x73c9ff5665d84067d98afbbeb2d9ff316c4b5bf885f9f3d31fa56eb1b13b3b90'; + +export const testTokenMap: RosenTokens = { + idKeys: {}, + tokens: [], +};