Skip to content
Open
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
b7d981a
[wallet/symbol/mobile] feat: make decimals font size smaller in Amoun…
OlegMakarenko Feb 19, 2026
4443659
[wallet/symbol/mobile] feat: add prop for custom section header in Fi…
OlegMakarenko Feb 19, 2026
94d1113
[wallet/symbol/mobile] feat: add Assets screen for owned tokens prese…
OlegMakarenko Feb 19, 2026
6284949
[wallet/symbol/mobile] feat: add tests for Assets screen
OlegMakarenko Feb 19, 2026
a2cb801
[wallet/symbol/mobile] fix: SelectToken component tests
OlegMakarenko Feb 19, 2026
decdf41
[wallet/symbol/mobile] feat: add Ethereum configuration to known-tokens
OlegMakarenko Feb 19, 2026
b33aa03
[wallet/symbol/mobile] feat: add more global JS-Doc types
OlegMakarenko Feb 27, 2026
a2f7d5e
[wallet/common/core] feat: add network currency JS-Doc type
OlegMakarenko Feb 27, 2026
86f77d8
[wallet/symbol/mobile] feat: add copy button to AccountView in TableView
OlegMakarenko Feb 27, 2026
30a22cd
[wallet/symbol/mobile] feat: add new icons and allow icon variant set…
OlegMakarenko Feb 27, 2026
3546a7f
[wallet/symbol/mobile] fix: remove hardcoded ticker from FeeSelector …
OlegMakarenko Feb 27, 2026
6c39326
[wallet/symbol/mobile] fix: add gap between content and title in Dial…
OlegMakarenko Feb 27, 2026
1225b92
[wallet/symbol/mobile] fix: remove static height in ButtonPlain compo…
OlegMakarenko Feb 27, 2026
862878a
[wallet/symbol/mobile] fix: add shrink style to AccountView component…
OlegMakarenko Feb 27, 2026
dc62203
[wallet/symbol/mobile] feat: add style property to TokenAvatar for be…
OlegMakarenko Feb 27, 2026
aff7cf6
[wallet/symbol/mobile] feat: add StatusRow component
OlegMakarenko Feb 27, 2026
53fdaeb
[wallet/symbol/mobile] feat: add Divider component
OlegMakarenko Feb 27, 2026
838b43e
[wallet/symbol/mobile] fix: add Divider to TransactionConfirmationDia…
OlegMakarenko Feb 27, 2026
7910d91
[wallet/symbol/mobile] feat: add modals property to TransactionScreen…
OlegMakarenko Feb 27, 2026
dfaa86a
[wallet/symbol/mobile] task: update global styles
OlegMakarenko Feb 27, 2026
93a3046
[wallet/symbol/mobile] feat: add getTotalFee amount to calculate tota…
OlegMakarenko Feb 27, 2026
f83ac40
[wallet/symbol/mobile] fix: amount validator
OlegMakarenko Feb 27, 2026
9cda044
[wallet/symbol/mobile] feat: add BridgeSwap and BridgeSwapDetails scr…
OlegMakarenko Feb 27, 2026
b160a98
[wallet/symbol/mobile] fix: bridge wallet controllers network type sy…
OlegMakarenko Feb 27, 2026
5a7fcc0
[wallet/symbol/mobile] feat: add TokenDetails screen, move EpiratonPr…
OlegMakarenko Mar 2, 2026
c79498b
[wallet/symbol/mobile] task: add TokenDetails navigation from Assets …
OlegMakarenko Mar 2, 2026
708ca09
[wallet/symbol/mobile] feat: add BridgeAccountList and BridgeAccountD…
OlegMakarenko Mar 2, 2026
b524dd1
[wallet/symbol/mobile] fix: AccountDetails layout and incorrect Table…
OlegMakarenko Mar 2, 2026
599e65f
[wallet/symbol/mobile] task: add new screens to Router
OlegMakarenko Mar 2, 2026
4ddd0ae
[wallet/symbol/mobile] feat: add localization keys
OlegMakarenko Mar 2, 2026
d4f6296
[wallet/symbol/mobile] feat: add default token selection passed via r…
OlegMakarenko Mar 2, 2026
66b5d07
[wallet/symbol/mobile] feat: add swap button to Home screen
OlegMakarenko Mar 2, 2026
cf2bc1e
[wallet/symbol/mobile] feat: add resolution for symbol.xym token crea…
OlegMakarenko Mar 2, 2026
1622fd1
[wallet/symbol/mobile] fix: JS-Doc and lint
OlegMakarenko Mar 2, 2026
b897793
[wallet/symbol/mobile] feat: add property to disable error message po…
OlegMakarenko Mar 2, 2026
0c9d05a
[wallet/symbol/mobile] fix: error handling on makeRequest helper
OlegMakarenko Mar 2, 2026
9130910
[wallet/common/core] fix: empty confg during data reload, inconsisten…
OlegMakarenko Mar 2, 2026
673e08d
[wallet/symbol/mobile] feat: add tests for useBridge hook
OlegMakarenko Mar 2, 2026
4c88df6
[wallet/symbol/mobile] feat: add tests for useBridgeAccounts hook
OlegMakarenko Mar 2, 2026
dac9ea7
[wallet/symbol/mobile] fix: failing tests
OlegMakarenko Mar 4, 2026
defed22
[wallet/symbol/mobile] feat: add tests for useSwapSelector hook, add …
OlegMakarenko Mar 4, 2026
3866dd9
[wallet/symbol/mobile] feat: add basic tests for useBridgeAmount, use…
OlegMakarenko Mar 4, 2026
aa96a1a
[wallet/symbol/mobile] fix: cleanup tests
OlegMakarenko Mar 4, 2026
0a35e48
[wallet/symbol/mobile] fix: tests console async warning
OlegMakarenko Mar 4, 2026
e75beb3
[wallet/symbol/mobile] feat: add tests for BridgeSwap screen
OlegMakarenko Mar 5, 2026
a8cc195
[wallet/symbol/mobile] fix: improve variables name case in bridge hoo…
OlegMakarenko Mar 6, 2026
e9db4c8
[wallet/symbol/mobile] feat: add tests for BridgeSwapDetails screen
OlegMakarenko Mar 6, 2026
5b8db14
[wallet/symbol/mobile] feat: add tests for BridgeAccountDetails screen
OlegMakarenko Mar 8, 2026
34047a0
[wallet/symbol/mobile] feat: add tests for BridgeAccountList screen
OlegMakarenko Mar 8, 2026
2fe4e1d
[wallet/symbol/mobile] feat: add tests for bridge utils
OlegMakarenko Mar 8, 2026
0ac086c
[wallet/symbol/mobile] feat: add tests for TokenDetails screen
OlegMakarenko Mar 8, 2026
802e95c
[wallet/common/core] fix: failing bridge tests
OlegMakarenko Mar 8, 2026
5ec37aa
[wallet/symbol/mobile] task: post-rebase - install dependencies, fix …
OlegMakarenko Mar 12, 2026
a01ede1
[wallet/symbol/mobile] fix: tests timezone issue on Jenkins
OlegMakarenko Mar 12, 2026
1a8c52d
[wallet/common] task: move address and hash normalization from Bridge…
OlegMakarenko Mar 23, 2026
837f6c8
[wallet/symbol/mobile] task: update TransactionFeeFixtureBuilder Ethe…
OlegMakarenko Mar 23, 2026
0d6afa7
[wallet/symbol/mobile] task: add extra check for token expiration war…
OlegMakarenko Mar 23, 2026
dc5322d
[wallet/symbol/mobile] task: add comments to BridgeSwap test (timers)
OlegMakarenko Mar 23, 2026
724dcef
[wallet/symbol/mobile] fix: lint
OlegMakarenko Mar 23, 2026
c334d2f
[wallet/symbol/mobile] fix: replace loading state with not configured…
OlegMakarenko Mar 24, 2026
2f620ce
[wallet/symbol/mobile] fix: move if statement in useBridgeAmount
OlegMakarenko Mar 24, 2026
71b22e5
[wallet/symbol/mobile] fix: remove empty lines in JS-Doc
OlegMakarenko Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 46 additions & 12 deletions wallet/common/core/src/lib/bridge/BridgeManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,32 @@ const BridgeMode = {
WRAP: 'wrap',
UNWRAP: 'unwrap'
};
const BROKEN_HASH_CHAIN_NAMES = ['ethereum']; // Chains for which bridge API returns transaction hashes without 0x prefix


/**
* Ensure that a string with 0x prefix is in correct case (lowercase).
*
* @param {string} hash - The hash to fix.
* @returns {string} - The fixed hash.
*/
const fix0xCase = hash => hash.startsWith('0x')
? `0x${hash.substring(2).toLowerCase()}`
: hash;

/**
* Ensure that transaction hash has 0x prefix for chains that are expected to have it, even if the bridge API returns it without.
*
* @param {string} hash - The hash to fix.
* @param {string} chainName - The name of the chain.
* @returns {string} - The fixed hash.
*/
const fixMissing0xTransactionHash = (hash, chainName) => {
if (BROKEN_HASH_CHAIN_NAMES.includes(chainName) && !hash.startsWith('0x'))
return `0x${hash.toLowerCase()}`;

return hash;
};

export class BridgeManager {
/** @type {WalletControllerWithBridgeModule} */
Expand Down Expand Up @@ -156,10 +182,6 @@ export class BridgeManager {
* @returns {Promise} - Promise that resolves when loading is complete.
*/
load = async () => {
// Clear config
this.#config = null;
this.#bridgeApi.setNetworkIdentifier(null);

// Get network identifiers from both wallet controllers
const nativeNetworkIdentifier = this.#nativeWalletController.networkIdentifier;
const wrappedNetworkIdentifier = this.#wrappedWalletController.networkIdentifier;
Expand Down Expand Up @@ -242,6 +264,9 @@ export class BridgeManager {
* @returns {Promise<BridgeRequest[]>} - List of requests.
*/
fetchSentRequests = async (mode, { pageSize, pageNumber } = {}) => {
if (!this.#config)
throw new Error('Failed to fetch sent requests. No bridge config fetched');

const walletController = this.#getSourceWalletController(mode);
const bridgeAddress = mode === BridgeMode.WRAP
? this.#config.nativeNetwork.bridgeAddress
Expand Down Expand Up @@ -360,6 +385,11 @@ export class BridgeManager {
#transactionToPendingRequest(transaction, context) {
const { mode, sourceToken, targetToken, sourceChainName, targetChainName } = context;

if (!sourceToken || !targetToken)
throw new Error('Failed to create pending request. Token info is not available');

const transactionTokens = transaction.mosaics ?? transaction.tokens ?? [];

return {
type: mode,
requestStatus: 'confirmed',
Expand All @@ -368,10 +398,11 @@ export class BridgeManager {
sourceTokenInfo: sourceToken,
targetTokenInfo: targetToken,
requestTransaction: {
signerAddress: transaction.senderAddress,
signerAddress: transaction.signerAddress,
hash: transaction.hash,
height: transaction.height,
timestamp: transaction.timestamp
timestamp: transaction.timestamp,
token: transactionTokens[0] ?? null
}
};
}
Expand All @@ -388,9 +419,12 @@ export class BridgeManager {
* @returns {BridgeRequest} - Mapped request object
*/
#requestFromDto(dto, { mode, sourceToken, targetToken, sourceChainName, targetChainName }) {
if (!sourceToken || !targetToken)
throw new Error('Failed to map request from DTO. Token info is not available');

const requestTransaction = {
signerAddress: dto.senderAddress,
hash: dto.requestTransactionHash,
signerAddress: fix0xCase(dto.senderAddress),
hash: fixMissing0xTransactionHash(dto.requestTransactionHash, sourceChainName),
height: dto.requestTransactionHeight ?? null,
timestamp: Math.trunc(dto.requestTimestamp * 1000),
token: {
Expand All @@ -399,8 +433,8 @@ export class BridgeManager {
}
};
const payoutTransaction = dto.payoutTransactionHash ? {
recipientAddress: dto.destinationAddress,
hash: dto.payoutTransactionHash,
recipientAddress: fix0xCase(dto.destinationAddress),
hash: fixMissing0xTransactionHash(dto.payoutTransactionHash, targetChainName),
height: dto.payoutTransactionHeight ?? null,
timestamp: Math.trunc(dto.payoutTimestamp * 1000),
token: {
Expand Down Expand Up @@ -440,8 +474,8 @@ export class BridgeManager {
*/
#errorFromDto(dto, { mode, sourceToken, targetToken, sourceChainName, targetChainName }) {
const requestTransaction = {
signerAddress: dto.senderAddress,
hash: dto.requestTransactionHash,
signerAddress: fix0xCase(dto.senderAddress),
hash: fixMissing0xTransactionHash(dto.requestTransactionHash, sourceChainName),
height: dto.requestTransactionHeight ?? null,
timestamp: Math.trunc(dto.requestTimestamp * 1000)
};
Expand Down
8 changes: 8 additions & 0 deletions wallet/common/core/src/types/Network.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@
* A map where the key is a network identifier and the value is another object/map with keys of type K and values of type V.
*/

/**
* @typedef {Object} NetworkCurrency
* @property {string} id - Token identifier.
* @property {number} divisibility - Token divisibility.
* @property {string} name - Token name or symbol.
*/

/**
* @typedef {Object} NetworkProperties
* @property {string} nodeUrl - API node URL.
* @property {string} networkIdentifier - Network identifier.
* @property {number} chainHeight - Chain height at the time of the request.
* @property {NetworkCurrency} networkCurrency - The native currency information for the network.
*/

export default {};
27 changes: 15 additions & 12 deletions wallet/common/core/tests/lib/BridgeManager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const SYMBOL_TOKEN_ID = '72C0212E67A08BCE';
const ETHEREUM_BRIDGE_ADDRESS = '0x9B5b717FEC711af80050986D1306D5c8Fb9FA953';
const ETHEREUM_TOKEN_ID = '0x5E8343A455F03109B737B6D8b410e4ECCE998cdA';
const ETHEREUM_ACCOUNT_ADDRESS = '0xeCA7dadA410614B604FFcBE0378C05474b0aeD8D';
const ETHEREUM_ADDRESS_FORMATTED = '0xeca7dada410614b604ffcbe0378c05474b0aed8d';

const BRIDGE_URL = 'https://bridge.example.com';
const BRIDGE_ID = 'symbol-ethereum-bridge';
Expand Down Expand Up @@ -427,8 +428,8 @@ describe('BridgeManager', () => {
token: createToken(SYMBOL_TOKEN_ID, '15')
},
payoutTransaction: {
recipientAddress: ETHEREUM_ACCOUNT_ADDRESS,
hash: 'C240B79CCC230438A685EB684A82DD81B58BD5A896805DC97A72D33F4812EEFF',
recipientAddress: ETHEREUM_ADDRESS_FORMATTED,
hash: '0xc240b79ccc230438a685eb684a82dd81b58bd5a896805dc97a72d33f4812eeff',
height: 49896,
timestamp: 1757430500000,
token: createToken(ETHEREUM_TOKEN_ID, '14.999999')
Expand Down Expand Up @@ -463,8 +464,8 @@ describe('BridgeManager', () => {
payoutConversionRate: '1',
payoutTotalFee: '0.0176',
requestTransaction: {
signerAddress: ETHEREUM_ACCOUNT_ADDRESS,
hash: 'D2C59C2516AE16728673B0BAF82753270FBCCB261D0212976A4FD3D885418F93',
signerAddress: ETHEREUM_ADDRESS_FORMATTED,
hash: '0xd2c59c2516ae16728673b0baf82753270fbccb261d0212976a4fd3d885418f93',
height: 8313,
timestamp: 1756931504000,
token: createToken(ETHEREUM_TOKEN_ID, '499.99999')
Expand Down Expand Up @@ -678,8 +679,8 @@ describe('BridgeManager', () => {
targetTokenInfo: createTokenInfo(SYMBOL_TOKEN_ID),
errorMessage: 'Oops',
requestTransaction: {
signerAddress: ETHEREUM_ACCOUNT_ADDRESS,
hash: 'ERR_UNWRAP',
signerAddress: ETHEREUM_ADDRESS_FORMATTED,
hash: '0xerr_unwrap',
height: 22,
timestamp: 111000
}
Expand Down Expand Up @@ -744,14 +745,14 @@ describe('BridgeManager', () => {
const pageNumber = 1;
const transactions = [
{
senderAddress: nativeWalletController.currentAccount.address,
signerAddress: nativeWalletController.currentAccount.address,
recipientAddress: lowerCaseBridge,
hash: 'PENDING_WRAP_HASH_1',
height: 100,
timestamp: 1000
},
{
senderAddress: nativeWalletController.currentAccount.address,
signerAddress: nativeWalletController.currentAccount.address,
recipientAddress: 'SOME_OTHER_ADDRESS',
hash: 'IGNORED_HASH',
height: 200,
Expand All @@ -770,7 +771,8 @@ describe('BridgeManager', () => {
signerAddress: nativeWalletController.currentAccount.address,
hash: 'PENDING_WRAP_HASH_1',
height: 100,
timestamp: 1000
timestamp: 1000,
token: null
}
}
];
Expand All @@ -792,14 +794,14 @@ describe('BridgeManager', () => {
const pageNumber = 2;
const transactions = [
{
senderAddress: wrappedWalletController.currentAccount.address,
signerAddress: wrappedWalletController.currentAccount.address,
recipientAddress: mixedCaseBridge,
hash: 'PENDING_UNWRAP_HASH_1',
height: 300,
timestamp: 2000
},
{
senderAddress: wrappedWalletController.currentAccount.address,
signerAddress: wrappedWalletController.currentAccount.address,
recipientAddress: '0xnotbridge',
hash: 'IGNORED_HASH_2',
height: 301,
Expand All @@ -818,7 +820,8 @@ describe('BridgeManager', () => {
signerAddress: wrappedWalletController.currentAccount.address,
hash: 'PENDING_UNWRAP_HASH_1',
height: 300,
timestamp: 2000
timestamp: 2000,
token: null
}
}
];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { walletStorageAccounts } from '__fixtures__/local/wallet';

const LINKED_KEYS = {
linkedPublicKey: '67599EEC06BE291E8608E3475D36E4C520389D6C853EA223CF9D744B47A4F630',
nodePublicKey: 'E4EAF960E8C4291AF1810F706E16750E3790237FDCF8887B4B0C1854603AD0FF',
Expand Down Expand Up @@ -76,7 +78,7 @@ export class AccountInfoFixtureBuilder {
...EMPTY_FIXTURE,
address: account.address,
publicKey: account.publicKey
});
}, chainName, networkIdentifier);
};

/**
Expand Down Expand Up @@ -234,4 +236,28 @@ export class AccountInfoFixtureBuilder {

return this;
};

/**
* Sets the tokens for the account.
*
* @param {Array} tokens - The account tokens.
* @returns {AccountInfoFixtureBuilder} The builder instance.
*/
setTokens = tokens => {
this._data.tokens = tokens;

return this;
};

/**
* Sets the mosaics for the account.
*
* @param {Array} mosaics - The account mosaics.
* @returns {AccountInfoFixtureBuilder} The builder instance.
*/
setMosaics = mosaics => {
this._data.mosaics = mosaics;

return this;
};
}
48 changes: 48 additions & 0 deletions wallet/symbol/mobile/__fixtures__/local/TokenFixtureBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,52 @@ export class TokenFixtureBuilder {

return this;
};

/**
* Sets the start height for the token.
*
* @param {number} startHeight - The token creation height.
* @returns {TokenFixtureBuilder} The builder instance.
*/
setStartHeight = startHeight => {
this._data.startHeight = startHeight;

return this;
};

/**
* Sets the end height for the token.
*
* @param {number} endHeight - The token expiration height.
* @returns {TokenFixtureBuilder} The builder instance.
*/
setEndHeight = endHeight => {
this._data.endHeight = endHeight;

return this;
};

/**
* Sets whether the token has unlimited duration (no expiration).
*
* @param {boolean} isUnlimitedDuration - True if the token has unlimited duration, false otherwise.
* @returns {TokenFixtureBuilder} The builder instance.
*/
setIsUnlimitedDuration = isUnlimitedDuration => {
this._data.isUnlimitedDuration = isUnlimitedDuration;

return this;
};

/**
* Sets the creator address for the token.
*
* @param {string} creator - The creator address.
* @returns {TokenFixtureBuilder} The builder instance.
*/
setCreator = creator => {
this._data.creator = creator;

return this;
};
}
Loading