66 Deserializer ,
77 Ed25519PublicKey ,
88 Ed25519Signature ,
9+ generateRawTransaction ,
910 Hex ,
1011 isPendingTransactionResponse ,
1112 isUserTransactionResponse ,
@@ -15,6 +16,7 @@ import {
1516 RawTransaction ,
1617 SignedTransaction ,
1718 TransactionAuthenticatorEd25519 ,
19+ TransactionPayload ,
1820} from '@aptos-labs/ts-sdk'
1921import type { AssetId , ChainId } from '@shapeshiftoss/caip'
2022import {
@@ -48,9 +50,14 @@ import type {
4850} from '../types'
4951import { ChainAdapterDisplayName , ValidAddressResultType } from '../types'
5052import { toAddressNList , verifyLedgerAppOpen } from '../utils'
51- import { APT_COIN_TYPE , FEE_STATEMENT_EVENT_TYPE , INDEXER_PAGE_LIMIT } from './constants'
53+ import {
54+ APT_COIN_TYPE ,
55+ FEE_STATEMENT_EVENT_TYPE ,
56+ INDEXER_PAGE_LIMIT ,
57+ TX_EXPIRY_SECS ,
58+ } from './constants'
5259import { parseAptosTx } from './parser'
53- import type { Token } from './types'
60+ import type { BuildCustomApiTxInput , Token } from './types'
5461import { getBalancePayload , getDecimalsPayload , getTransferPayload } from './utils'
5562
5663export interface ChainAdapterArgs {
@@ -77,6 +84,7 @@ export class ChainAdapter implements IChainAdapter<KnownChainIds.AptosMainnet> {
7784 fullnode : `${ args . rpcUrl } /v1` ,
7885 indexer : `${ args . indexerUrl } /v1/graphql` ,
7986 clientConfig : args . apiKey ? { API_KEY : args . apiKey } : undefined ,
87+ transactionGenerationConfig : { defaultTxnExpirySecFromNow : TX_EXPIRY_SECS } ,
8088 } ) ,
8189 )
8290 }
@@ -272,31 +280,62 @@ export class ChainAdapter implements IChainAdapter<KnownChainIds.AptosMainnet> {
272280 data : getTransferPayload ( to , value , contractAddress ) ,
273281 } )
274282
275- // the sdk floors max gas at 2000 units, which would reserve far more apt than the fee
276- const { sender, sequence_number, payload, expiration_timestamp_secs, chain_id } =
277- rawTransaction
278-
279- const transaction = new RawTransaction (
280- sender ,
281- sequence_number ,
282- payload ,
283- BigInt ( maxGasAmount ) ,
284- BigInt ( gasUnitPrice ) ,
285- expiration_timestamp_secs ,
286- chain_id ,
287- )
283+ return this . toSignTx ( rawTransaction , { accountNumber, gasUnitPrice, maxGasAmount } )
284+ } catch ( err ) {
285+ return ErrorHandler ( err , {
286+ translation : 'chainAdapters.errors.buildTransaction' ,
287+ } )
288+ }
289+ }
288290
289- return {
290- addressNList : toAddressNList ( this . getBip44Params ( { accountNumber } ) ) ,
291- rawTransactionBytes : transaction . bcsToBytes ( ) ,
292- }
291+ async buildCustomApiTx (
292+ input : BuildCustomApiTxInput ,
293+ ) : Promise < SignTx < KnownChainIds . AptosMainnet > > {
294+ try {
295+ const { from, accountNumber, payload, gasUnitPrice, maxGasAmount } = input
296+
297+ const rawTransaction = await generateRawTransaction ( {
298+ aptosConfig : this . client . config ,
299+ sender : from ,
300+ payload : TransactionPayload . deserialize (
301+ new Deserializer ( Hex . fromHexInput ( payload ) . toUint8Array ( ) ) ,
302+ ) ,
303+ } )
304+
305+ return this . toSignTx ( rawTransaction , { accountNumber, gasUnitPrice, maxGasAmount } )
293306 } catch ( err ) {
294307 return ErrorHandler ( err , {
295308 translation : 'chainAdapters.errors.buildTransaction' ,
296309 } )
297310 }
298311 }
299312
313+ private toSignTx (
314+ rawTransaction : RawTransaction ,
315+ {
316+ accountNumber,
317+ gasUnitPrice,
318+ maxGasAmount,
319+ } : Pick < BuildCustomApiTxInput , 'accountNumber' | 'gasUnitPrice' | 'maxGasAmount' > ,
320+ ) : SignTx < KnownChainIds . AptosMainnet > {
321+ const { sender, sequence_number, payload, expiration_timestamp_secs, chain_id } = rawTransaction
322+
323+ const transaction = new RawTransaction (
324+ sender ,
325+ sequence_number ,
326+ payload ,
327+ BigInt ( maxGasAmount ) ,
328+ BigInt ( gasUnitPrice ) ,
329+ expiration_timestamp_secs ,
330+ chain_id ,
331+ )
332+
333+ return {
334+ addressNList : toAddressNList ( this . getBip44Params ( { accountNumber } ) ) ,
335+ rawTransactionBytes : transaction . bcsToBytes ( ) ,
336+ }
337+ }
338+
300339 async buildSendTransaction ( input : BuildSendTxInput < KnownChainIds . AptosMainnet > ) : Promise < {
301340 txToSign : SignTx < KnownChainIds . AptosMainnet >
302341 } > {
@@ -388,23 +427,18 @@ export class ChainAdapter implements IChainAdapter<KnownChainIds.AptosMainnet> {
388427 const { to, value, chainSpecific } = input
389428 const { from, contractAddress } = chainSpecific
390429
391- // gas doesn't depend on the amount, and an apt amount near the balance can't cover gas in simulation
392- const simulatedValue = contractAddress ? value : '1'
393-
394430 const [ { gas_estimate, prioritized_gas_estimate, deprioritized_gas_estimate } , transaction ] =
395431 await Promise . all ( [
396432 this . client . getGasPriceEstimation ( ) ,
397433 this . client . transaction . build . simple ( {
398434 sender : from ,
399- data : getTransferPayload ( to , simulatedValue , contractAddress ) ,
435+ data : getTransferPayload ( to , value , contractAddress ) ,
436+ // sets the zero address as fee payer, which simulation accepts without checking anyone's gas balance
437+ withFeePayer : true ,
400438 } ) ,
401439 ] )
402440
403- // caps simulated gas at what the sender can afford, so the default cap can't fail the simulation
404- const [ sim ] = await this . client . transaction . simulate . simple ( {
405- transaction,
406- options : { estimateGasUnitPrice : true , estimateMaxGasAmount : true } ,
407- } )
441+ const [ sim ] = await this . client . transaction . simulate . simple ( { transaction } )
408442
409443 if ( ! sim ?. success ) throw new Error ( `transaction simulation failed: ${ sim ?. vm_status } ` )
410444
0 commit comments