Skip to content

Commit ea9e284

Browse files
authored
fix: account for ATA creation in Solana fee queries (#1185)
Signed-off-by: bennett <bennett@umaproject.org>
1 parent 5c4bc97 commit ea9e284

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@across-protocol/sdk",
33
"author": "UMA Team",
4-
"version": "4.3.42",
4+
"version": "4.3.43",
55
"license": "AGPL-3.0",
66
"homepage": "https://docs.across.to/reference/sdk",
77
"files": [

src/relayFeeCalculator/chain-queries/svmQuery.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import assert from "assert";
2-
import { getComputeUnitEstimateForTransactionMessageFactory, TransactionSigner } from "@solana/kit";
3-
import { SVMProvider, SolanaVoidSigner, getFillRelayTx } from "../../arch/svm";
2+
import {
3+
getComputeUnitEstimateForTransactionMessageFactory,
4+
TransactionSigner,
5+
fetchEncodedAccount,
6+
isSome,
7+
} from "@solana/kit";
8+
import { SVMProvider, SolanaVoidSigner, getFillRelayTx, toAddress, getAssociatedTokenAddress } from "../../arch/svm";
49
import { Coingecko } from "../../coingecko";
510
import { CHAIN_IDs } from "../../constants";
611
import { getGasPriceEstimate } from "../../gasPriceOracle";
712
import { RelayData } from "../../interfaces";
813
import { Address, BigNumber, BigNumberish, SvmAddress, TransactionCostEstimate, toBN } from "../../utils";
914
import { Logger, QueryInterface, getDefaultRelayer } from "../relayFeeCalculator";
1015
import { SymbolMappingType } from "./";
16+
import { TOKEN_PROGRAM_ADDRESS } from "@solana-program/token";
17+
import { TOKEN_2022_PROGRAM_ADDRESS, getTokenSize, fetchMint, Extension } from "@solana-program/token-2022";
1118

1219
/**
1320
* A special QueryBase implementation for SVM used for querying gas costs, token prices, and decimals of various tokens
@@ -76,24 +83,49 @@ export class SvmQuery implements QueryInterface {
7683
repaymentAddress
7784
);
7885

79-
const [computeUnitsConsumed, gasPriceEstimate] = await Promise.all([
86+
const [computeUnitsConsumed, gasPriceEstimate, tokenAccountInfo] = await Promise.all([
8087
toBN(await this.computeUnitEstimator(fillRelayTx)),
8188
getGasPriceEstimate(this.provider, {
8289
unsignedTx: fillRelayTx,
8390
baseFeeMultiplier: options.baseFeeMultiplier,
8491
priorityFeeMultiplier: options.priorityFeeMultiplier,
8592
}),
93+
this.provider.getAccountInfo(toAddress(outputToken), { encoding: "base58" }).send(),
8694
]);
8795

96+
// If the owner of the token account is not the token program, then we can assume that it is the 2022 token program address, in which
97+
// case we need to determine the extensions the token has to properly calculate rent exemption.
98+
const tokenOwner = tokenAccountInfo!.value!.owner;
99+
assert(
100+
tokenOwner === TOKEN_2022_PROGRAM_ADDRESS || tokenOwner === TOKEN_PROGRAM_ADDRESS,
101+
`${outputToken} has invalid token account owner ${tokenOwner}.`
102+
);
103+
const recipientAta = await getAssociatedTokenAddress(recipient, outputToken, tokenOwner);
104+
const encodedAta = await fetchEncodedAccount(this.provider, recipientAta);
105+
88106
// We can cast the gas price estimate to an SvmGasPriceEstimate here since the oracle should always
89107
// query the Solana adapter.
90108
const gasPrice = gasPriceEstimate.baseFee.add(
91109
gasPriceEstimate.microLamportsPerComputeUnit.mul(computeUnitsConsumed).div(toBN(1_000_000)) // 1_000_000 microLamports/lamport.
92110
);
111+
let tokenGasCost = gasPrice;
112+
113+
// If the ATA does not exist, we need to factor the rent amount into the token gas cost.
114+
if (!encodedAta.exists) {
115+
// If the ATA is a non-2022 token, then it will always have a fixed size of 165.
116+
let extensions: Extension[] | undefined = undefined;
117+
if (tokenOwner === TOKEN_2022_PROGRAM_ADDRESS) {
118+
const mint = await fetchMint(this.provider, toAddress(outputToken));
119+
extensions = isSome(mint.data.extensions) ? mint.data.extensions.value : undefined;
120+
}
121+
const tokenAccountSize = getTokenSize(extensions);
122+
const rentCostInLamports = await this.provider.getMinimumBalanceForRentExemption(BigInt(tokenAccountSize)).send();
123+
tokenGasCost = tokenGasCost.add(toBN(Number(rentCostInLamports)));
124+
}
93125

94126
return {
95127
nativeGasCost: computeUnitsConsumed,
96-
tokenGasCost: gasPrice,
128+
tokenGasCost,
97129
gasPrice,
98130
};
99131
}

0 commit comments

Comments
 (0)