Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 10 additions & 1 deletion packages/bridge-status-controller/src/strategy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
isBitcoinTrade,
isEvmTxData,
isNonEvmChainId,
isStellarTrade,
isTronTrade,
StellarTradeData,
Trade,
TronTradeData,
TxData,
Expand All @@ -20,7 +22,12 @@ import { submitNonEvmHandler } from './non-evm-strategy';
import type { SubmitStrategyParams, SubmitStepResult } from './types';

const validateParams = <
TxDataType extends BitcoinTradeData | TronTradeData | string | TxData,
TxDataType extends
| BitcoinTradeData
| StellarTradeData
| TronTradeData
| string
| TxData,
>(
params: SubmitStrategyParams<Trade>,
): params is SubmitStrategyParams<TxDataType> => {
Expand All @@ -38,6 +45,8 @@ const validateParams = <
return txs.every((tx) => typeof tx === 'string');
case ChainId.BTC:
return txs.every(isBitcoinTrade);
case ChainId.STELLAR:
return txs.every((tx) => typeof tx === 'string' || isStellarTrade(tx));
case ChainId.TRON:
return txs.every(isTronTrade);
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { isTronChainId } from '@metamask/bridge-controller';
import type {
BitcoinTradeData,
StellarTradeData,
TronTradeData,
TxData,
} from '@metamask/bridge-controller';
Expand All @@ -20,7 +21,7 @@ import type { SubmitStrategyParams, SubmitStepResult } from './types';
*/
const handleTronApproval = async (
args: SubmitStrategyParams<
TronTradeData | BitcoinTradeData | string | TxData
TronTradeData | BitcoinTradeData | StellarTradeData | string | TxData
>,
) => {
const {
Expand Down Expand Up @@ -65,7 +66,7 @@ const handleTronApproval = async (
*/
export async function* submitNonEvmHandler(
args: SubmitStrategyParams<
BitcoinTradeData | TronTradeData | string | TxData
BitcoinTradeData | StellarTradeData | TronTradeData | string | TxData
>,
): AsyncGenerator<SubmitStepResult, void, void> {
const {
Expand Down
35 changes: 27 additions & 8 deletions packages/bridge-status-controller/src/utils/snaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
TransactionType,
} from '@metamask/transaction-controller';
import type { TransactionMeta } from '@metamask/transaction-controller';
import type { CaipChainId, Hex } from '@metamask/utils';
import type { CaipAssetType, CaipChainId, Hex } from '@metamask/utils';
import { v4 as uuid } from 'uuid';

import type {
Expand Down Expand Up @@ -72,25 +72,42 @@ export const createClientTransactionRequest = (
* @param srcChainId - The source chain ID
* @param accountId - The account ID
* @param snapId - The snap ID
* @param sourceAssetId - The source asset ID
* @param destAssetId - The destination asset ID
* @returns The snap request object for signing and sending transaction
*/
export const getClientRequest = (
trade: Trade,
srcChainId: number,
accountId: AccountsControllerState['internalAccounts']['accounts'][string]['id'],
snapId: string,
sourceAssetId?: CaipAssetType,
destAssetId?: CaipAssetType,
): Parameters<SnapController['handleRequest']>[0] => {
const scope = formatChainIdToCaip(srcChainId);

const transaction = extractTradeData(trade);

// Tron trades need the visible flag and contract type to be included in the request options
const options = isTronTrade(trade)
? {
visible: trade.visible,
type: trade.raw_data?.contract?.[0]?.type,
}
: undefined;
let options: Record<string, unknown> | undefined;

if (sourceAssetId !== undefined || destAssetId !== undefined) {
options = {
...(sourceAssetId !== undefined && {
sourceAssetId,
}),
...(destAssetId !== undefined && {
destAssetId,
}),
};
}

if (isTronTrade(trade)) {
// Tron trades need the visible flag and contract type to be included in the request options
options = {
visible: trade.visible,
type: trade.raw_data?.contract?.[0]?.type,
};
}

return createClientTransactionRequest(
snapId,
Expand Down Expand Up @@ -250,6 +267,8 @@ export const handleNonEvmTx = async (
quoteResponse.quote.srcChainId,
selectedAccount.id,
selectedAccount.metadata?.snap?.id,
quoteResponse.quote.srcAsset.assetId,
quoteResponse.quote.destAsset.assetId,
);
const requestResponse = (await messenger.call(
'SnapController:handleRequest',
Expand Down
82 changes: 82 additions & 0 deletions packages/bridge-status-controller/src/utils/transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
FeeType,
formatChainIdToCaip,
formatChainIdToHex,
getNativeAssetForChainId,
} from '@metamask/bridge-controller';
import type {
QuoteMetadata,
Expand Down Expand Up @@ -1669,6 +1670,87 @@ describe('Bridge Status Controller Transaction Utils', () => {

createClientRequestSpy.mockRestore();
});

it('should include Stellar source and destination asset IDs as options when trade is not Tron', () => {
const stellarTrade = {
xdrBase64: 'AAAABg==',
} as never;

const mockAccount = {
id: 'test-account-id',
metadata: {
snap: { id: 'test-snap-id' },
},
};

const sourceAssetId = getNativeAssetForChainId(ChainId.STELLAR).assetId;
const destAssetId = getNativeAssetForChainId(ChainId.ETH).assetId;

const result = snaps.getClientRequest(
stellarTrade,
ChainId.STELLAR,
mockAccount.id,
mockAccount.metadata.snap.id,
sourceAssetId,
destAssetId,
);

expect(result).toMatchObject({
origin: 'metamask',
snapId: 'test-snap-id',
handler: 'onClientRequest',
request: {
id: expect.any(String),
jsonrpc: '2.0',
method: 'signAndSendTransaction',
params: {
transaction: 'AAAABg==',
scope: formatChainIdToCaip(ChainId.STELLAR),
accountId: 'test-account-id',
options: {
sourceAssetId,
destAssetId,
},
},
},
});
});

it('should omit destAssetId option for Stellar trades when destination asset ID is not provided', () => {
const stellarTrade = {
xdr: 'AAAABg==',
} as never;

const mockAccount = {
id: 'test-account-id',
metadata: {
snap: { id: 'test-snap-id' },
},
};

const sourceAssetId = getNativeAssetForChainId(ChainId.STELLAR).assetId;

const result = snaps.getClientRequest(
stellarTrade,
ChainId.STELLAR,
mockAccount.id,
mockAccount.metadata.snap.id,
sourceAssetId,
);

expect(result).toMatchObject({
request: {
params: {
options: {
sourceAssetId,
},
},
},
});
expect(
(result.request.params as { options: Record<string, unknown> }).options,
).not.toHaveProperty('destAssetId');
});
});

describe('getAddTransactionBatchParams', () => {
Expand Down
Loading