Skip to content

Commit 96f3d34

Browse files
committed
feat(sdk-coin-sol): big endian support for verifyTransaction
TICKET: WP-6284
1 parent 8361510 commit 96f3d34

File tree

1 file changed

+45
-3
lines changed
  • modules/sdk-coin-sol/src

1 file changed

+45
-3
lines changed

modules/sdk-coin-sol/src/sol.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,41 @@ export interface SolConsolidationRecoveryOptions extends MPCConsolidationRecover
178178
const HEX_REGEX = /^[0-9a-fA-F]+$/;
179179
const BLIND_SIGNING_TX_TYPES_TO_CHECK = { enabletoken: 'AssociatedTokenAccountInitialization' };
180180

181+
/**
182+
* Get amount string corrected for architecture-specific endianness issues.
183+
*
184+
* On s390x (big-endian) architecture, the Solana transaction parser (via @solana/web3.js)
185+
* incorrectly reads little-endian u64 amounts as big-endian, resulting in corrupted values.
186+
*
187+
* This function corrects all amounts on s390x by swapping byte order to undo
188+
* the incorrect byte order that happened during transaction parsing.
189+
*
190+
* @param amount - The amount to check and potentially fix
191+
* @returns The corrected amount as a string
192+
*/
193+
function getAmountBasedOnEndianness(amount: string | number): string {
194+
const amountStr = String(amount);
195+
196+
// Only s390x architecture has this endianness issue
197+
const isS390x = process.arch === 's390x';
198+
if (!isS390x) {
199+
return amountStr;
200+
}
201+
202+
try {
203+
const amountBN = BigInt(amountStr);
204+
// On s390x, the parser ALWAYS reads u64 as big-endian when it's actually little-endian
205+
// So we ALWAYS need to swap bytes to get the correct value
206+
const buf = Buffer.alloc(8);
207+
buf.writeBigUInt64BE(amountBN, 0);
208+
const fixed = buf.readBigUInt64LE(0);
209+
return fixed.toString();
210+
} catch (e) {
211+
// If conversion fails, return original value
212+
return amountStr;
213+
}
214+
}
215+
181216
export class Sol extends BaseCoin {
182217
protected readonly _staticsCoin: Readonly<StaticsBaseCoin>;
183218

@@ -371,8 +406,12 @@ export class Sol extends BaseCoin {
371406
const recipientFromTx = filteredOutputs[index]; // This address should be an ATA
372407

373408
// Compare the BigNumber values because amount is (string | number)
374-
const userAmount = new BigNumber(recipientFromUser.amount);
375-
const txAmount = new BigNumber(recipientFromTx.amount);
409+
// Apply s390x endianness fix if needed
410+
const userAmountStr = String(recipientFromUser.amount);
411+
const txAmountStr = getAmountBasedOnEndianness(recipientFromTx.amount);
412+
413+
const userAmount = new BigNumber(userAmountStr);
414+
const txAmount = new BigNumber(txAmountStr);
376415
if (!userAmount.isEqualTo(txAmount)) {
377416
return false;
378417
}
@@ -459,10 +498,13 @@ export class Sol extends BaseCoin {
459498
const explainedTxTotal: Record<string, BigNumber> = {};
460499

461500
for (const output of explainedTx.outputs) {
501+
// Apply s390x endianness fix to output amounts before summing
502+
const outputAmountStr = getAmountBasedOnEndianness(output.amount);
503+
462504
// total output amount based on each token
463505
const assetName = output.tokenName || this.getChain();
464506
const amount = explainedTxTotal[assetName] || new BigNumber(0);
465-
explainedTxTotal[assetName] = amount.plus(output.amount);
507+
explainedTxTotal[assetName] = amount.plus(outputAmountStr);
466508
}
467509

468510
if (!_.isEqual(explainedTxTotal, totalAmount)) {

0 commit comments

Comments
 (0)