@avalabs/fusion-sdk 0.14.4 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +6 -2
  2. package/dist/constants.cjs.map +1 -1
  3. package/dist/constants.js.map +1 -1
  4. package/dist/errors.cjs +1 -1
  5. package/dist/errors.cjs.map +1 -1
  6. package/dist/errors.d.cts +62 -1
  7. package/dist/errors.d.ts +62 -1
  8. package/dist/errors.js +1 -1
  9. package/dist/errors.js.map +1 -1
  10. package/dist/mod.cjs +1 -1
  11. package/dist/mod.d.cts +2 -2
  12. package/dist/mod.d.ts +2 -2
  13. package/dist/mod.js +1 -1
  14. package/dist/quoter/constants.cjs +1 -1
  15. package/dist/quoter/constants.js +1 -1
  16. package/dist/quoter/constants.js.map +1 -1
  17. package/dist/quoter/quoter.cjs +1 -1
  18. package/dist/quoter/quoter.cjs.map +1 -1
  19. package/dist/quoter/quoter.d.ts +0 -3
  20. package/dist/quoter/quoter.js +1 -1
  21. package/dist/quoter/quoter.js.map +1 -1
  22. package/dist/transfer-service/_evm-errors.cjs +2 -0
  23. package/dist/transfer-service/_evm-errors.cjs.map +1 -0
  24. package/dist/transfer-service/_evm-errors.js +2 -0
  25. package/dist/transfer-service/_evm-errors.js.map +1 -0
  26. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.cjs +1 -1
  27. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.cjs.map +1 -1
  28. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.js +1 -1
  29. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.js.map +1 -1
  30. package/dist/transfer-service/lombard/_utils/fee.js +1 -1
  31. package/dist/transfer-service/lombard/_utils/fee.js.map +1 -1
  32. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.cjs +1 -1
  33. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.cjs.map +1 -1
  34. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.js +1 -1
  35. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/estimate-native-fee.js.map +1 -1
  36. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.cjs +1 -1
  37. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.cjs.map +1 -1
  38. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.js +1 -1
  39. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/track-transfer.js.map +1 -1
  40. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.cjs +1 -1
  41. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.cjs.map +1 -1
  42. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.js +1 -1
  43. package/dist/transfer-service/lombard/btc-to-btcb/_handlers/transfer-asset.js.map +1 -1
  44. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.cjs +1 -1
  45. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.cjs.map +1 -1
  46. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.js +1 -1
  47. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/estimate-native-fee.js.map +1 -1
  48. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.cjs +1 -1
  49. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.cjs.map +1 -1
  50. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.js +1 -1
  51. package/dist/transfer-service/lombard/btcb-to-btc/_handlers/transfer-asset.js.map +1 -1
  52. package/dist/transfer-service/lombard/constants.cjs +1 -1
  53. package/dist/transfer-service/lombard/constants.js +1 -1
  54. package/dist/transfer-service/lombard/constants.js.map +1 -1
  55. package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs +1 -1
  56. package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs.map +1 -1
  57. package/dist/transfer-service/markr/_handlers/estimate-native-fee.js +1 -1
  58. package/dist/transfer-service/markr/_handlers/estimate-native-fee.js.map +1 -1
  59. package/dist/transfer-service/markr/_handlers/track-transfer.cjs +1 -1
  60. package/dist/transfer-service/markr/_handlers/track-transfer.cjs.map +1 -1
  61. package/dist/transfer-service/markr/_handlers/track-transfer.js +1 -1
  62. package/dist/transfer-service/markr/_handlers/track-transfer.js.map +1 -1
  63. package/dist/transfer-service/markr/_handlers/transfer-asset.cjs +1 -1
  64. package/dist/transfer-service/markr/_handlers/transfer-asset.cjs.map +1 -1
  65. package/dist/transfer-service/markr/_handlers/transfer-asset.js +1 -1
  66. package/dist/transfer-service/markr/_handlers/transfer-asset.js.map +1 -1
  67. package/dist/transfer-service/markr/_utils.cjs +1 -1
  68. package/dist/transfer-service/markr/_utils.cjs.map +1 -1
  69. package/dist/transfer-service/markr/_utils.js +1 -1
  70. package/dist/transfer-service/markr/_utils.js.map +1 -1
  71. package/dist/transfer-service/markr/constants.cjs +1 -1
  72. package/dist/transfer-service/markr/constants.js +1 -1
  73. package/dist/transfer-service/markr/constants.js.map +1 -1
  74. package/dist/transfer-service/markr/markr-service.cjs +1 -1
  75. package/dist/transfer-service/markr/markr-service.cjs.map +1 -1
  76. package/dist/transfer-service/markr/markr-service.js +1 -1
  77. package/dist/transfer-service/markr/markr-service.js.map +1 -1
  78. package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.cjs +1 -1
  79. package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.cjs.map +1 -1
  80. package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.js +1 -1
  81. package/dist/transfer-service/wrap-unwrap/_handlers/estimate-native-fee.js.map +1 -1
  82. package/dist/transfer-service/wrap-unwrap/_utils.cjs +1 -1
  83. package/dist/transfer-service/wrap-unwrap/_utils.cjs.map +1 -1
  84. package/dist/transfer-service/wrap-unwrap/_utils.js +1 -1
  85. package/dist/transfer-service/wrap-unwrap/_utils.js.map +1 -1
  86. package/dist/types/service.d.cts +11 -49
  87. package/dist/types/service.d.ts +11 -49
  88. package/dist/utils/price-impact.cjs +1 -1
  89. package/dist/utils/price-impact.cjs.map +1 -1
  90. package/dist/utils/price-impact.d.cts +1 -0
  91. package/dist/utils/price-impact.d.ts +1 -0
  92. package/dist/utils/price-impact.js +1 -1
  93. package/dist/utils/price-impact.js.map +1 -1
  94. package/dist/utils/solana.cjs +2 -0
  95. package/dist/utils/solana.cjs.map +1 -0
  96. package/dist/utils/solana.js +2 -0
  97. package/dist/utils/solana.js.map +1 -0
  98. package/package.json +6 -6
  99. package/dist/transfer-service/markr/_solana-utils.cjs +0 -2
  100. package/dist/transfer-service/markr/_solana-utils.cjs.map +0 -1
  101. package/dist/transfer-service/markr/_solana-utils.js +0 -2
  102. package/dist/transfer-service/markr/_solana-utils.js.map +0 -1
@@ -57,27 +57,15 @@ interface NativeFeeEstimate {
57
57
  /** The native asset used for the fee */
58
58
  readonly asset: NativeAsset;
59
59
  /**
60
- * @deprecated Use `totalUpfrontFee` instead. The value is the same, but is being renamed for clarity.
60
+ * The total estimated fee amount in the smallest unit of the asset (e.g., wei for ETH, lamports for SOL).
61
+ *
62
+ * This value is buffered via the `feeUnitsMarginBps` option in `estimateNativeFee` to account for estimation inaccuracies.
61
63
  */
62
64
  readonly totalFee: bigint;
63
65
  /**
64
- * Total upfront native amount required in the smallest native units
65
- * (e.g., wei for EVM, lamports for Solana, satoshis for Bitcoin).
66
- *
67
- * This is intended for preflight balance checks before initiating a transfer.
68
- *
69
- * In the case of EVM, if an allowance approval is required, this includes
70
- * both swap and approval fee requirements. In the case of Solana, this includes
71
- * execution fees plus any rent that must be funded upfront.
66
+ * The `totalFee` without any margin (ie `feeUnitsMarginBps`) applied.
72
67
  */
73
- readonly totalUpfrontFee: bigint;
74
- /**
75
- * Portion of `totalUpfrontFee` that is expected to be refunded to the user.
76
- *
77
- * For example, in Solana this may include lamports returned when temporary
78
- * accounts are closed in the same transaction.
79
- */
80
- readonly refundable?: bigint;
68
+ readonly totalFeeWithoutMargin: bigint;
81
69
  /**
82
70
  * Breakdown information of fee calculation.
83
71
  *
@@ -94,47 +82,21 @@ interface NativeFeeEstimate {
94
82
  * Approval fee estimate for transactions that require an approval (e.g., ERC20 allowance approval).
95
83
  */
96
84
  approvalFee?: bigint;
97
- baseFee?: bigint;
98
- priorityFee?: bigint;
99
85
  /**
100
- * Rent lamports included in `totalFee` for Solana transactions.
101
- *
102
- * This is the upfront rent requirement used in preflight balance checks.
86
+ * Solana base fee estimate returned from RPC simulation (in lamports).
103
87
  */
104
- rentFee?: bigint;
105
- /**
106
- * Net rent lamports expected to be spent after accounting for same-transaction
107
- * account-close refunds.
108
- *
109
- * This is useful for understanding expected final cost.
110
- */
111
- rentFeeNet?: bigint;
88
+ baseFee?: bigint;
112
89
  /**
113
- * Accounts inferred as being created during the transaction and considered
114
- * in rent estimation.
115
- *
116
- * - `kind`: inferred account category (e.g., ATA or system account).
117
- * - `lamports`: rent or funding lamports associated with creation.
118
- * - `refunded`: whether the created account appears to be closed and refunded
119
- * back to the sender in the same transaction.
90
+ * Solana priority fee estimate calculated from compute unit estimation (in lamports).
120
91
  */
121
- createdAccounts?: ReadonlyArray<{
122
- address: string;
123
- kind: string;
124
- lamports: bigint;
125
- refunded: boolean;
126
- }>;
92
+ priorityFee?: bigint;
127
93
  [key: string]: unknown | undefined;
128
94
  }>;
129
95
  }
130
96
  interface EstimateNativeFeeOptions {
131
97
  /**
132
- * A safety margin to apply to the fee unit calculations
133
- * (e.g., gas units for EVM, compute units for Solana).
134
- *
135
- * For example, a value of `500` would add a 5% margin to the estimated
136
- * units to account for estimation inaccuracy, and the fee would be
137
- * calculated based on this increased unit estimate.
98
+ * A safety margin to native fee estimation, applied as a percentage buffer
99
+ * to the estimated fee to account for estimation inaccuracies.
138
100
  *
139
101
  * Value must be a non-negative integer, where 100 bps = 1% margin.
140
102
  *
@@ -57,27 +57,15 @@ interface NativeFeeEstimate {
57
57
  /** The native asset used for the fee */
58
58
  readonly asset: NativeAsset;
59
59
  /**
60
- * @deprecated Use `totalUpfrontFee` instead. The value is the same, but is being renamed for clarity.
60
+ * The total estimated fee amount in the smallest unit of the asset (e.g., wei for ETH, lamports for SOL).
61
+ *
62
+ * This value is buffered via the `feeUnitsMarginBps` option in `estimateNativeFee` to account for estimation inaccuracies.
61
63
  */
62
64
  readonly totalFee: bigint;
63
65
  /**
64
- * Total upfront native amount required in the smallest native units
65
- * (e.g., wei for EVM, lamports for Solana, satoshis for Bitcoin).
66
- *
67
- * This is intended for preflight balance checks before initiating a transfer.
68
- *
69
- * In the case of EVM, if an allowance approval is required, this includes
70
- * both swap and approval fee requirements. In the case of Solana, this includes
71
- * execution fees plus any rent that must be funded upfront.
66
+ * The `totalFee` without any margin (ie `feeUnitsMarginBps`) applied.
72
67
  */
73
- readonly totalUpfrontFee: bigint;
74
- /**
75
- * Portion of `totalUpfrontFee` that is expected to be refunded to the user.
76
- *
77
- * For example, in Solana this may include lamports returned when temporary
78
- * accounts are closed in the same transaction.
79
- */
80
- readonly refundable?: bigint;
68
+ readonly totalFeeWithoutMargin: bigint;
81
69
  /**
82
70
  * Breakdown information of fee calculation.
83
71
  *
@@ -94,47 +82,21 @@ interface NativeFeeEstimate {
94
82
  * Approval fee estimate for transactions that require an approval (e.g., ERC20 allowance approval).
95
83
  */
96
84
  approvalFee?: bigint;
97
- baseFee?: bigint;
98
- priorityFee?: bigint;
99
85
  /**
100
- * Rent lamports included in `totalFee` for Solana transactions.
101
- *
102
- * This is the upfront rent requirement used in preflight balance checks.
86
+ * Solana base fee estimate returned from RPC simulation (in lamports).
103
87
  */
104
- rentFee?: bigint;
105
- /**
106
- * Net rent lamports expected to be spent after accounting for same-transaction
107
- * account-close refunds.
108
- *
109
- * This is useful for understanding expected final cost.
110
- */
111
- rentFeeNet?: bigint;
88
+ baseFee?: bigint;
112
89
  /**
113
- * Accounts inferred as being created during the transaction and considered
114
- * in rent estimation.
115
- *
116
- * - `kind`: inferred account category (e.g., ATA or system account).
117
- * - `lamports`: rent or funding lamports associated with creation.
118
- * - `refunded`: whether the created account appears to be closed and refunded
119
- * back to the sender in the same transaction.
90
+ * Solana priority fee estimate calculated from compute unit estimation (in lamports).
120
91
  */
121
- createdAccounts?: ReadonlyArray<{
122
- address: string;
123
- kind: string;
124
- lamports: bigint;
125
- refunded: boolean;
126
- }>;
92
+ priorityFee?: bigint;
127
93
  [key: string]: unknown | undefined;
128
94
  }>;
129
95
  }
130
96
  interface EstimateNativeFeeOptions {
131
97
  /**
132
- * A safety margin to apply to the fee unit calculations
133
- * (e.g., gas units for EVM, compute units for Solana).
134
- *
135
- * For example, a value of `500` would add a 5% margin to the estimated
136
- * units to account for estimation inaccuracy, and the fee would be
137
- * calculated based on this increased unit estimate.
98
+ * A safety margin to native fee estimation, applied as a percentage buffer
99
+ * to the estimated fee to account for estimation inaccuracies.
138
100
  *
139
101
  * Value must be a non-negative integer, where 100 bps = 1% margin.
140
102
  *
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);let e=require(`viem`);const t=[`partner`];async function n({amountIn:n,amountOut:r,assetIn:i,assetOut:a,fees:o,targetChain:s},c){let l=o.filter(n=>!t.includes(n.type)||n.fundingModel!==`included`||n.chainId!==s.chainId||n.token.type!==a.type?!1:`address`in n.token&&`address`in a?n.token.type===`erc20`&&a.type===`erc20`?(0,e.isAddressEqual)(n.token.address,a.address):n.token.address===a.address:!0).reduce((e,t)=>e+t.amount,r),[u,d]=await c({asset:i,amount:n},{asset:a,amount:l});return u===null||d===null?null:(u-d)/u*1e4}exports.calculatePriceImpactFromQuote=n;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);let e=require(`viem`);async function t({amountIn:t,amountOut:n,assetIn:r,assetOut:i,fees:a,sourceChain:o,targetChain:s},c){let l=a.filter(t=>t.fundingModel!==`included`||t.chainId!==o.chainId||t.token.type!==r.type?!1:`address`in t.token&&`address`in r?t.token.type===`erc20`&&r.type===`erc20`?(0,e.isAddressEqual)(t.token.address,r.address):t.token.address===r.address:!0).reduce((e,t)=>e-t.amount,t),u=a.filter(t=>t.fundingModel!==`included`||t.chainId!==s.chainId||t.token.type!==i.type?!1:`address`in t.token&&`address`in i?t.token.type===`erc20`&&i.type===`erc20`?(0,e.isAddressEqual)(t.token.address,i.address):t.token.address===i.address:!0).reduce((e,t)=>e+t.amount,n),[d,f]=await c({asset:r,amount:l},{asset:i,amount:u});return d===null||f===null?null:(d-f)/d*1e4}exports.calculatePriceImpactFromQuote=t;
2
2
  //# sourceMappingURL=price-impact.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"price-impact.cjs","names":[],"sources":["../../src/utils/price-impact.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport type { Quote, QuoteFeeType } from '../types/quote';\nimport type { Asset } from '../types/asset';\n\nconst FEE_TYPE_FILTER: readonly QuoteFeeType[] = ['partner'];\n\n/**\n * Calculates quote price impact in basis points using USD valuations for the input and output assets.\n *\n * Included fees that are deducted from the output asset are added back to `amountOut` so the comparison\n * reflects the pre-deduction output value.\n *\n * @param quote - Quote to evaluate.\n * @param getTokenUsdValues - Resolver that returns USD values for the input and adjusted output amounts.\n * @returns Price impact in basis points, or `null` when either USD value is unavailable.\n */\nexport async function calculatePriceImpactFromQuote(\n { amountIn, amountOut, assetIn, assetOut, fees, targetChain }: Quote,\n getTokenUsdValues: (\n input: { asset: Asset; amount: bigint },\n output: { asset: Asset; amount: bigint },\n ) => Promise<[inputUsd: number | null, outputUsd: number | null]>,\n): Promise<number | null> {\n const adjustedAmountOut: bigint = fees\n .filter((fee) => {\n if (\n !FEE_TYPE_FILTER.includes(fee.type) ||\n fee.fundingModel !== 'included' ||\n fee.chainId !== targetChain.chainId ||\n fee.token.type !== assetOut.type\n ) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetOut) {\n if (fee.token.type === 'erc20' && assetOut.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetOut.address);\n }\n\n return fee.token.address === assetOut.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc + fee.amount, amountOut);\n\n const [inputUsd, outputUsd] = await getTokenUsdValues(\n { asset: assetIn, amount: amountIn },\n { asset: assetOut, amount: adjustedAmountOut },\n );\n\n if (inputUsd === null || outputUsd === null) {\n return null;\n }\n\n const priceImpactBps = ((inputUsd - outputUsd) / inputUsd) * 10_000;\n\n return priceImpactBps;\n}\n"],"mappings":"mEAIA,MAAM,EAA2C,CAAC,UAAU,CAY5D,eAAsB,EACpB,CAAE,WAAU,YAAW,UAAS,WAAU,OAAM,eAChD,EAIwB,CACxB,IAAM,EAA4B,EAC/B,OAAQ,GAEL,CAAC,EAAgB,SAAS,EAAI,KAAK,EACnC,EAAI,eAAiB,YACrB,EAAI,UAAY,EAAY,SAC5B,EAAI,MAAM,OAAS,EAAS,KAErB,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAS,OAAS,SAClD,EAAA,EAAA,gBAAsB,EAAI,MAAM,QAAS,EAAS,QAAQ,CAGrD,EAAI,MAAM,UAAY,EAAS,QAGjC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAU,CAE9C,CAAC,EAAU,GAAa,MAAM,EAClC,CAAE,MAAO,EAAS,OAAQ,EAAU,CACpC,CAAE,MAAO,EAAU,OAAQ,EAAmB,CAC/C,CAQD,OANI,IAAa,MAAQ,IAAc,KAC9B,MAGgB,EAAW,GAAa,EAAY"}
1
+ {"version":3,"file":"price-impact.cjs","names":[],"sources":["../../src/utils/price-impact.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport type { Quote } from '../types/quote';\nimport type { Asset } from '../types/asset';\n\n/**\n * Calculates quote price impact in basis points using USD valuations for the input and output assets.\n *\n * Included fees that are deducted from the output asset are added back to `amountOut` so the comparison\n * reflects the pre-deduction output value.\n *\n * @param quote - Quote to evaluate.\n * @param getTokenUsdValues - Resolver that returns USD values for the input and adjusted output amounts.\n * @returns Price impact in basis points, or `null` when either USD value is unavailable.\n */\nexport async function calculatePriceImpactFromQuote(\n { amountIn, amountOut, assetIn, assetOut, fees, sourceChain, targetChain }: Quote,\n getTokenUsdValues: (\n input: { asset: Asset; amount: bigint },\n output: { asset: Asset; amount: bigint },\n ) => Promise<[inputUsd: number | null, outputUsd: number | null]>,\n): Promise<number | null> {\n const adjustedAmountIn: bigint = fees\n .filter((fee) => {\n if (fee.fundingModel !== 'included' || fee.chainId !== sourceChain.chainId || fee.token.type !== assetIn.type) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetIn) {\n if (fee.token.type === 'erc20' && assetIn.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetIn.address);\n }\n\n return fee.token.address === assetIn.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc - fee.amount, amountIn);\n\n const adjustedAmountOut: bigint = fees\n .filter((fee) => {\n if (fee.fundingModel !== 'included' || fee.chainId !== targetChain.chainId || fee.token.type !== assetOut.type) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetOut) {\n if (fee.token.type === 'erc20' && assetOut.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetOut.address);\n }\n\n return fee.token.address === assetOut.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc + fee.amount, amountOut);\n\n const [inputUsd, outputUsd] = await getTokenUsdValues(\n { asset: assetIn, amount: adjustedAmountIn },\n { asset: assetOut, amount: adjustedAmountOut },\n );\n\n if (inputUsd === null || outputUsd === null) {\n return null;\n }\n\n const priceImpactBps = ((inputUsd - outputUsd) / inputUsd) * 10_000;\n\n return priceImpactBps;\n}\n"],"mappings":"mEAcA,eAAsB,EACpB,CAAE,WAAU,YAAW,UAAS,WAAU,OAAM,cAAa,eAC7D,EAIwB,CACxB,IAAM,EAA2B,EAC9B,OAAQ,GACH,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,SAAW,EAAI,MAAM,OAAS,EAAQ,KAChG,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAQ,OAAS,SACjD,EAAA,EAAA,gBAAsB,EAAI,MAAM,QAAS,EAAQ,QAAQ,CAGpD,EAAI,MAAM,UAAY,EAAQ,QAGhC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAS,CAE7C,EAA4B,EAC/B,OAAQ,GACH,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,SAAW,EAAI,MAAM,OAAS,EAAS,KACjG,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAS,OAAS,SAClD,EAAA,EAAA,gBAAsB,EAAI,MAAM,QAAS,EAAS,QAAQ,CAGrD,EAAI,MAAM,UAAY,EAAS,QAGjC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAU,CAE9C,CAAC,EAAU,GAAa,MAAM,EAClC,CAAE,MAAO,EAAS,OAAQ,EAAkB,CAC5C,CAAE,MAAO,EAAU,OAAQ,EAAmB,CAC/C,CAQD,OANI,IAAa,MAAQ,IAAc,KAC9B,MAGgB,EAAW,GAAa,EAAY"}
@@ -18,6 +18,7 @@ declare function calculatePriceImpactFromQuote({
18
18
  assetIn,
19
19
  assetOut,
20
20
  fees,
21
+ sourceChain,
21
22
  targetChain
22
23
  }: Quote, getTokenUsdValues: (input: {
23
24
  asset: Asset;
@@ -18,6 +18,7 @@ declare function calculatePriceImpactFromQuote({
18
18
  assetIn,
19
19
  assetOut,
20
20
  fees,
21
+ sourceChain,
21
22
  targetChain
22
23
  }: Quote, getTokenUsdValues: (input: {
23
24
  asset: Asset;
@@ -1,2 +1,2 @@
1
- import{isAddressEqual as e}from"viem";const t=[`partner`];async function n({amountIn:n,amountOut:r,assetIn:i,assetOut:a,fees:o,targetChain:s},c){let l=o.filter(n=>!t.includes(n.type)||n.fundingModel!==`included`||n.chainId!==s.chainId||n.token.type!==a.type?!1:`address`in n.token&&`address`in a?n.token.type===`erc20`&&a.type===`erc20`?e(n.token.address,a.address):n.token.address===a.address:!0).reduce((e,t)=>e+t.amount,r),[u,d]=await c({asset:i,amount:n},{asset:a,amount:l});return u===null||d===null?null:(u-d)/u*1e4}export{n as calculatePriceImpactFromQuote};
1
+ import{isAddressEqual as e}from"viem";async function t({amountIn:t,amountOut:n,assetIn:r,assetOut:i,fees:a,sourceChain:o,targetChain:s},c){let l=a.filter(t=>t.fundingModel!==`included`||t.chainId!==o.chainId||t.token.type!==r.type?!1:`address`in t.token&&`address`in r?t.token.type===`erc20`&&r.type===`erc20`?e(t.token.address,r.address):t.token.address===r.address:!0).reduce((e,t)=>e-t.amount,t),u=a.filter(t=>t.fundingModel!==`included`||t.chainId!==s.chainId||t.token.type!==i.type?!1:`address`in t.token&&`address`in i?t.token.type===`erc20`&&i.type===`erc20`?e(t.token.address,i.address):t.token.address===i.address:!0).reduce((e,t)=>e+t.amount,n),[d,f]=await c({asset:r,amount:l},{asset:i,amount:u});return d===null||f===null?null:(d-f)/d*1e4}export{t as calculatePriceImpactFromQuote};
2
2
  //# sourceMappingURL=price-impact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"price-impact.js","names":[],"sources":["../../src/utils/price-impact.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport type { Quote, QuoteFeeType } from '../types/quote';\nimport type { Asset } from '../types/asset';\n\nconst FEE_TYPE_FILTER: readonly QuoteFeeType[] = ['partner'];\n\n/**\n * Calculates quote price impact in basis points using USD valuations for the input and output assets.\n *\n * Included fees that are deducted from the output asset are added back to `amountOut` so the comparison\n * reflects the pre-deduction output value.\n *\n * @param quote - Quote to evaluate.\n * @param getTokenUsdValues - Resolver that returns USD values for the input and adjusted output amounts.\n * @returns Price impact in basis points, or `null` when either USD value is unavailable.\n */\nexport async function calculatePriceImpactFromQuote(\n { amountIn, amountOut, assetIn, assetOut, fees, targetChain }: Quote,\n getTokenUsdValues: (\n input: { asset: Asset; amount: bigint },\n output: { asset: Asset; amount: bigint },\n ) => Promise<[inputUsd: number | null, outputUsd: number | null]>,\n): Promise<number | null> {\n const adjustedAmountOut: bigint = fees\n .filter((fee) => {\n if (\n !FEE_TYPE_FILTER.includes(fee.type) ||\n fee.fundingModel !== 'included' ||\n fee.chainId !== targetChain.chainId ||\n fee.token.type !== assetOut.type\n ) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetOut) {\n if (fee.token.type === 'erc20' && assetOut.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetOut.address);\n }\n\n return fee.token.address === assetOut.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc + fee.amount, amountOut);\n\n const [inputUsd, outputUsd] = await getTokenUsdValues(\n { asset: assetIn, amount: amountIn },\n { asset: assetOut, amount: adjustedAmountOut },\n );\n\n if (inputUsd === null || outputUsd === null) {\n return null;\n }\n\n const priceImpactBps = ((inputUsd - outputUsd) / inputUsd) * 10_000;\n\n return priceImpactBps;\n}\n"],"mappings":"sCAIA,MAAM,EAA2C,CAAC,UAAU,CAY5D,eAAsB,EACpB,CAAE,WAAU,YAAW,UAAS,WAAU,OAAM,eAChD,EAIwB,CACxB,IAAM,EAA4B,EAC/B,OAAQ,GAEL,CAAC,EAAgB,SAAS,EAAI,KAAK,EACnC,EAAI,eAAiB,YACrB,EAAI,UAAY,EAAY,SAC5B,EAAI,MAAM,OAAS,EAAS,KAErB,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAS,OAAS,QAC3C,EAAe,EAAI,MAAM,QAAS,EAAS,QAAQ,CAGrD,EAAI,MAAM,UAAY,EAAS,QAGjC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAU,CAE9C,CAAC,EAAU,GAAa,MAAM,EAClC,CAAE,MAAO,EAAS,OAAQ,EAAU,CACpC,CAAE,MAAO,EAAU,OAAQ,EAAmB,CAC/C,CAQD,OANI,IAAa,MAAQ,IAAc,KAC9B,MAGgB,EAAW,GAAa,EAAY"}
1
+ {"version":3,"file":"price-impact.js","names":[],"sources":["../../src/utils/price-impact.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport type { Quote } from '../types/quote';\nimport type { Asset } from '../types/asset';\n\n/**\n * Calculates quote price impact in basis points using USD valuations for the input and output assets.\n *\n * Included fees that are deducted from the output asset are added back to `amountOut` so the comparison\n * reflects the pre-deduction output value.\n *\n * @param quote - Quote to evaluate.\n * @param getTokenUsdValues - Resolver that returns USD values for the input and adjusted output amounts.\n * @returns Price impact in basis points, or `null` when either USD value is unavailable.\n */\nexport async function calculatePriceImpactFromQuote(\n { amountIn, amountOut, assetIn, assetOut, fees, sourceChain, targetChain }: Quote,\n getTokenUsdValues: (\n input: { asset: Asset; amount: bigint },\n output: { asset: Asset; amount: bigint },\n ) => Promise<[inputUsd: number | null, outputUsd: number | null]>,\n): Promise<number | null> {\n const adjustedAmountIn: bigint = fees\n .filter((fee) => {\n if (fee.fundingModel !== 'included' || fee.chainId !== sourceChain.chainId || fee.token.type !== assetIn.type) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetIn) {\n if (fee.token.type === 'erc20' && assetIn.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetIn.address);\n }\n\n return fee.token.address === assetIn.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc - fee.amount, amountIn);\n\n const adjustedAmountOut: bigint = fees\n .filter((fee) => {\n if (fee.fundingModel !== 'included' || fee.chainId !== targetChain.chainId || fee.token.type !== assetOut.type) {\n return false;\n }\n\n if ('address' in fee.token && 'address' in assetOut) {\n if (fee.token.type === 'erc20' && assetOut.type === 'erc20') {\n return isAddressEqual(fee.token.address, assetOut.address);\n }\n\n return fee.token.address === assetOut.address;\n }\n\n return true;\n })\n .reduce((acc, fee) => acc + fee.amount, amountOut);\n\n const [inputUsd, outputUsd] = await getTokenUsdValues(\n { asset: assetIn, amount: adjustedAmountIn },\n { asset: assetOut, amount: adjustedAmountOut },\n );\n\n if (inputUsd === null || outputUsd === null) {\n return null;\n }\n\n const priceImpactBps = ((inputUsd - outputUsd) / inputUsd) * 10_000;\n\n return priceImpactBps;\n}\n"],"mappings":"sCAcA,eAAsB,EACpB,CAAE,WAAU,YAAW,UAAS,WAAU,OAAM,cAAa,eAC7D,EAIwB,CACxB,IAAM,EAA2B,EAC9B,OAAQ,GACH,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,SAAW,EAAI,MAAM,OAAS,EAAQ,KAChG,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAQ,OAAS,QAC1C,EAAe,EAAI,MAAM,QAAS,EAAQ,QAAQ,CAGpD,EAAI,MAAM,UAAY,EAAQ,QAGhC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAS,CAE7C,EAA4B,EAC/B,OAAQ,GACH,EAAI,eAAiB,YAAc,EAAI,UAAY,EAAY,SAAW,EAAI,MAAM,OAAS,EAAS,KACjG,GAGL,YAAa,EAAI,OAAS,YAAa,EACrC,EAAI,MAAM,OAAS,SAAW,EAAS,OAAS,QAC3C,EAAe,EAAI,MAAM,QAAS,EAAS,QAAQ,CAGrD,EAAI,MAAM,UAAY,EAAS,QAGjC,GACP,CACD,QAAQ,EAAK,IAAQ,EAAM,EAAI,OAAQ,EAAU,CAE9C,CAAC,EAAU,GAAa,MAAM,EAClC,CAAE,MAAO,EAAS,OAAQ,EAAkB,CAC5C,CAAE,MAAO,EAAU,OAAQ,EAAmB,CAC/C,CAQD,OANI,IAAa,MAAQ,IAAc,KAC9B,MAGgB,EAAW,GAAa,EAAY"}
@@ -0,0 +1,2 @@
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../errors.cjs`);let t=require(`@solana/kit`);const n=1000000n;function r(e){let n=(0,t.getBase64Encoder)().encode(e);return(0,t.getTransactionDecoder)().decode(n)}function i(n){try{(0,t.getBase64Encoder)().encode(n)}catch(t){throw new e.SdkError(`Unable to decode transaction`,e.ErrorCode.INVALID_PARAMS,{cause:t,details:`Unable to decode base64 transaction into Base64EncodedWireTransaction`})}}function a(e){if(typeof e==`string`)return{errorName:e};let t=Object.entries(e)[0];if(!t)return{errorName:`Unknown`,reason:`Unable to map Solana transaction error to details - no error information found`};let[n,r]=t;return{errorName:n,args:Array.isArray(r)?r:[r]}}function o(e,t){if(e.errorName===`InsufficientFundsForFee`||e.errorName===`InsufficientFundsForRent`)return[!0,!0];if(e.errorName===`InstructionError`&&e.args&&e.args[1]===`InsufficientFunds`)return[!0,!1];if(t){for(let e of t)if(/insufficient lamports/i.test(e))return[!0,!0]}return[!1,!1]}function s(e){return BigInt(Object.keys(e.signatures).length)}function c(e){let n=(0,t.getCompiledTransactionMessageDecoder)().decode(e.messageBytes),r=0n,i=0n,a=e=>{if(e.length<1)return;let t=e[0],n=new DataView(e.buffer,e.byteOffset,e.byteLength);if(t===2&&e.length>=5){r=BigInt(n.getUint32(1,!0));return}t===3&&e.length>=9&&(i=n.getBigUint64(1,!0))};if(n.version===1){let e=Math.min(n.numInstructions,n.instructionHeaders.length,n.instructionPayloads.length);for(let t=0;t<e;t++){let e=n.instructionHeaders[t],r=n.instructionPayloads[t];!e||!r||n.staticAccounts[e.programAccountIndex]===`ComputeBudget111111111111111111111111111111`&&a(r.instructionData)}return{computeUnitLimit:r,computeUnitPriceMicroLamports:i}}for(let e of n.instructions){if(n.staticAccounts[e.programAddressIndex]!==`ComputeBudget111111111111111111111111111111`)continue;let t=e.data;t&&a(t)}return{computeUnitLimit:r,computeUnitPriceMicroLamports:i}}function l(e,t){return e<=0n||t<=0n?0n:(e*t+(n-1n))/n}async function u(t,n,{signal:u}={}){i(n);let d=await f(n,t),p=(await t.simulateTransaction(d,{encoding:`base64`,innerInstructions:!0,replaceRecentBlockhash:!0,sigVerify:!1}).send({abortSignal:u})).value;if(p.err){let t=a(p.err),[n,r]=o(t,p.logs),i;throw n&&(i=new e.InsufficientFundsError({errorCode:e.ErrorCode.SOLANA_ERROR,insufficientTokenWasNative:r,details:`Simulation failed due to insufficient funds${r?` for fee`:``}.`})),new e.EstimateNativeFeeError({cause:i,details:t,errorCode:e.ErrorCode.SOLANA_ERROR,tx:d})}let m=r(d),h=s(m)*5000n,{computeUnitLimit:g,computeUnitPriceMicroLamports:_}=c(m),v=l(g,_),y=p.fee??h+v,b=p.unitsConsumed==null?0n:p.unitsConsumed,x=p.preBalances??[],S=p.postBalances??[];return{baseFeeLamports:h,computeUnitLimit:g,computeUnitPriceMicroLamports:_,feePayerBalanceDiffLamports:(x[0]??0n)-(S[0]??0n),networkFeeLamports:y,priorityFeeLamports:v,unitsConsumed:b}}async function d(e,n){return await(0,t.decompileTransactionMessageFetchingLookupTables)((0,t.getCompiledTransactionMessageDecoder)().decode(e.messageBytes),n)}async function f(e,n){let i=r(e),[a,o]=await Promise.all([d(i,n),n.getLatestBlockhash().send()]);return(0,t.getBase64EncodedWireTransaction)((0,t.compileTransaction)((0,t.setTransactionMessageLifetimeUsingBlockhash)(o.value,a)))}exports.estimateSolanaFee=u,exports.refreshSolanaSwapTransactionBlockhash=f;
2
+ //# sourceMappingURL=solana.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.cjs","names":["SdkError","ErrorCode","InsufficientFundsError","EstimateNativeFeeError"],"sources":["../../src/utils/solana.ts"],"sourcesContent":["import {\n compileTransaction,\n createSolanaRpc,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getBase64Encoder,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SignaturesMap,\n type SolanaRpcApi,\n type TransactionError,\n type TransactionMessageBytes,\n} from '@solana/kit';\nimport { splitCaip2ChainId } from './caip';\nimport {\n ErrorCode,\n EstimateNativeFeeError,\n InsufficientFundsError,\n InvalidParamsError,\n SdkError,\n type EstimateNativeFeeErrorDetails,\n} from '../errors';\nimport type { Chain } from '../types/chain';\n\n/** Index of the fee payer in a Solana transaction. */\nexport const SOLANA_FEE_PAYER_INDEX = 0;\n\n/**\n * Compute Budget program address.\n *\n * Used to detect `SetComputeUnitPrice` instructions when deriving\n * the Solana priority fee component from transaction message bytes.\n */\nexport const SOLANA_COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';\n\n/**\n * System Program address.\n *\n * Used to detect account-creation instructions and extract lamports\n * funded upfront for newly created system accounts.\n */\nexport const SOLANA_SYSTEM_PROGRAM = '11111111111111111111111111111111';\n\n/**\n * Associated Token Account (ATA) program address.\n *\n * Used to detect ATA create instructions so the estimator can include\n * rent-exempt funding when the ATA does not already exist on-chain.\n */\nexport const SOLANA_ASSOCIATED_TOKEN_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';\n\n/**\n * Legacy SPL Token program address.\n *\n * Used to detect close-account instructions that may refund lamports\n * from temporary token accounts back to the sender.\n */\nexport const SOLANA_SPL_TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';\n\n/**\n * SPL Token-2022 program address.\n *\n * Used alongside the legacy token program for close-account detection\n * when computing expected refundable lamports.\n */\nexport const SOLANA_SPL_TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';\n\n/**\n * SPL token account size for rent-exemption calculations.\n *\n * Used with `getMinimumBalanceForRentExemption` to estimate ATA\n * creation funding requirements.\n */\nexport const SPL_TOKEN_ACCOUNT_SIZE_BYTES = 165n;\nexport const SOLANA_BASE_FEE_PER_SIGNATURE_LAMPORTS = 5_000n;\nexport const MICRO_LAMPORTS_PER_LAMPORT = 1_000_000n;\n\n/**\n * Creates a Solana RPC client for the given chain.\n *\n * @param chain - The chain for which to create the Solana RPC client. Must be a Solana chain.\n * @returns A Solana RPC client instance.\n * @throws {InvalidParamsError} If the provided chain is not a Solana chain.\n */\nexport function getSolanaRpcForChain(chain: Chain): Rpc<SolanaRpcApi> {\n const { namespace } = splitCaip2ChainId(chain.chainId);\n\n if (namespace !== 'solana') {\n throw new InvalidParamsError('Can not create Solana RPC', 'Provided chain is not a Solana chain');\n }\n\n return createSolanaRpc(chain.rpcUrl);\n}\n\n/**\n * Decoded representation of a Solana transaction, including the message bytes and signatures.\n */\nexport type DecodedSolanaTransaction = Readonly<{ messageBytes: TransactionMessageBytes; signatures: SignaturesMap }>;\n\n/**\n * Decodes a base64-encoded Solana transaction into its message bytes and signatures.\n *\n * @param base64Tx - The base64-encoded Solana transaction string.\n * @returns An object containing the decoded message bytes and signatures.\n * @throws {Error} If the transaction cannot be decoded.\n */\nexport function decodeSolanaBase64Transaction(base64Tx: string): DecodedSolanaTransaction {\n const base64Encoder = getBase64Encoder();\n const transactionBytes = base64Encoder.encode(base64Tx);\n\n const transactionDecoder = getTransactionDecoder();\n\n return transactionDecoder.decode(transactionBytes);\n}\n\n/**\n * Encodes a decoded Solana transaction (message bytes and signatures) into\n * a base64-encoded string suitable for sending via RPC.\n *\n * @param transaction - The decoded Solana transaction containing message bytes and signatures.\n * @returns A base64-encoded string representing the Solana transaction.\n * @throws {Error} If the transaction cannot be encoded.\n */\nexport function encodeSolanaTransactionToBase64(transaction: DecodedSolanaTransaction): Base64EncodedWireTransaction {\n return getBase64EncodedWireTransaction(transaction);\n}\n\n/**\n * Asserts that a given string is a valid base64-encoded Solana transaction.\n *\n * @param base64Tx - The string to validate as a base64-encoded Solana transaction.\n * @throws {SdkError} If the string is not a valid base64-encoded Solana transaction.\n */\nexport function assertSolanaBase64Transaction(base64Tx: string): asserts base64Tx is Base64EncodedWireTransaction {\n try {\n const base64Encoder = getBase64Encoder();\n base64Encoder.encode(base64Tx);\n } catch (error) {\n throw new SdkError('Unable to decode transaction', ErrorCode.INVALID_PARAMS, {\n cause: error,\n details: 'Unable to decode base64 transaction into Base64EncodedWireTransaction',\n });\n }\n}\n\ntype ExtractTransactionErrorString<T extends TransactionError> = T extends string ? T : keyof T;\n\ntype TransactionErrorString = ExtractTransactionErrorString<TransactionError> | 'Unknown';\n\ninterface EstimateNativeFeeErrorDetailsWithRequiredErrorName extends EstimateNativeFeeErrorDetails {\n errorName: TransactionErrorString;\n}\n\nexport function mapTransactionErrorToEstimateNativeFeeErrorDetails(\n err: TransactionError,\n): EstimateNativeFeeErrorDetailsWithRequiredErrorName {\n if (typeof err === 'string') {\n return { errorName: err };\n }\n\n const errorEntries = Object.entries(err);\n\n const error = errorEntries[0];\n\n if (!error) {\n return {\n errorName: 'Unknown',\n reason: 'Unable to map Solana transaction error to details - no error information found',\n };\n }\n\n const [errorName, errorArgs] = error;\n\n return {\n errorName: errorName as TransactionErrorString,\n args: Array.isArray(errorArgs) ? errorArgs : [errorArgs],\n };\n}\n\nfunction isErrorInsufficientFunds(\n errorDetails: EstimateNativeFeeErrorDetailsWithRequiredErrorName,\n logs?: readonly string[] | null,\n): [isInsufficientFundsError: boolean, isNativeFundsIssue: boolean] {\n if (errorDetails.errorName === 'InsufficientFundsForFee' || errorDetails.errorName === 'InsufficientFundsForRent') {\n return [true, true];\n }\n\n if (\n errorDetails.errorName === 'InstructionError' &&\n errorDetails.args &&\n errorDetails.args[1] === 'InsufficientFunds'\n ) {\n return [true, false];\n }\n\n if (logs) {\n // Look for /insufficient lamports/ error in logs, if found return [true, true].\n for (const log of logs) {\n if (/insufficient lamports/i.test(log)) {\n return [true, true];\n }\n }\n }\n\n return [false, false];\n}\n\nexport function getSignaturesCountFromDecodedTransaction(decodedTransaction: DecodedSolanaTransaction): bigint {\n return BigInt(Object.keys(decodedTransaction.signatures).length);\n}\n\nexport function getComputeUnitBudgetPriceAndLimit(decodedTransaction: DecodedSolanaTransaction): {\n computeUnitLimit: bigint;\n computeUnitPriceMicroLamports: bigint;\n} {\n type TransactionInstructionData = {\n readonly [index: number]: number;\n readonly buffer: ArrayBufferLike;\n readonly byteLength: number;\n readonly byteOffset: number;\n readonly length: number;\n };\n\n const compiledTxMessage = getCompiledTransactionMessageDecoder().decode(decodedTransaction.messageBytes);\n let computeUnitLimit = 0n;\n let computeUnitPriceMicroLamports = 0n;\n\n const updateBudgetValuesFromData = (data: TransactionInstructionData): void => {\n if (data.length < 1) {\n return;\n }\n\n const discriminator = data[0];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // ComputeBudget::SetComputeUnitLimit(u32)\n if (discriminator === 2 && data.length >= 1 + 4) {\n computeUnitLimit = BigInt(view.getUint32(1, true));\n return;\n }\n\n // ComputeBudget::SetComputeUnitPrice(u64)\n if (discriminator === 3 && data.length >= 1 + 8) {\n computeUnitPriceMicroLamports = view.getBigUint64(1, true);\n }\n };\n\n if (compiledTxMessage.version === 1) {\n const maxInstructionCount = Math.min(\n compiledTxMessage.numInstructions,\n compiledTxMessage.instructionHeaders.length,\n compiledTxMessage.instructionPayloads.length,\n );\n\n for (let instructionIndex = 0; instructionIndex < maxInstructionCount; instructionIndex++) {\n const instructionHeader = compiledTxMessage.instructionHeaders[instructionIndex];\n const instructionPayload = compiledTxMessage.instructionPayloads[instructionIndex];\n if (!instructionHeader || !instructionPayload) {\n continue;\n }\n\n const programAddress = compiledTxMessage.staticAccounts[instructionHeader.programAccountIndex];\n if (programAddress !== SOLANA_COMPUTE_BUDGET_PROGRAM) {\n continue;\n }\n\n updateBudgetValuesFromData(instructionPayload.instructionData);\n }\n\n return { computeUnitLimit, computeUnitPriceMicroLamports };\n }\n\n for (const instruction of compiledTxMessage.instructions) {\n const programAddress = compiledTxMessage.staticAccounts[instruction.programAddressIndex];\n if (programAddress !== SOLANA_COMPUTE_BUDGET_PROGRAM) {\n continue;\n }\n\n const data = instruction.data;\n if (!data) {\n continue;\n }\n\n updateBudgetValuesFromData(data);\n }\n\n return { computeUnitLimit, computeUnitPriceMicroLamports };\n}\n\nexport function calculatePriorityFeeLamports(computeUnitLimit: bigint, computeUnitPriceMicroLamports: bigint): bigint {\n if (computeUnitLimit <= 0n || computeUnitPriceMicroLamports <= 0n) {\n return 0n;\n }\n\n return (\n (computeUnitLimit * computeUnitPriceMicroLamports + (MICRO_LAMPORTS_PER_LAMPORT - 1n)) / MICRO_LAMPORTS_PER_LAMPORT\n );\n}\n\ntype SimulateTransactionBaseValue = Awaited<\n ReturnType<ReturnType<Rpc<SolanaRpcApi>['simulateTransaction']>['send']>\n>['value'];\n\ninterface SimulateTransactionRuntimeExtras {\n readonly fee?: bigint;\n readonly preBalances?: readonly bigint[];\n readonly postBalances?: readonly bigint[];\n // readonly preTokenBalances?: readonly unknown[];\n // readonly postTokenBalances?: readonly unknown[];\n readonly loadedAddresses?: Readonly<{\n readonly readonly: readonly string[];\n readonly writable: readonly string[];\n }>;\n // readonly innerInstructions?: readonly unknown[] | null;\n}\n\ntype EnhancedSimulateTransactionValue = SimulateTransactionBaseValue & SimulateTransactionRuntimeExtras;\n\nexport async function estimateSolanaFee(\n rpc: Rpc<SolanaRpcApi>,\n base64EncodedWireTransaction: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<\n Readonly<{\n baseFeeLamports: bigint;\n computeUnitLimit: bigint;\n computeUnitPriceMicroLamports: bigint;\n /**\n * Total consumed lamports for transaction.\n *\n * If transaction swap input amount was in native SOL,\n * subtract the total input value (input amount + additive fee SOL) from\n * this value to get the total fee cost for the transaction.\n */\n feePayerBalanceDiffLamports: bigint;\n /** The sum of base fee and priority fee */\n networkFeeLamports: bigint;\n priorityFeeLamports: bigint;\n unitsConsumed: bigint;\n }>\n> {\n assertSolanaBase64Transaction(base64EncodedWireTransaction);\n const refreshedBase64EncodedWireTransaction = await refreshSolanaSwapTransactionBlockhash(\n base64EncodedWireTransaction,\n rpc,\n );\n\n const simulation = await rpc\n .simulateTransaction(refreshedBase64EncodedWireTransaction, {\n encoding: 'base64',\n innerInstructions: true,\n replaceRecentBlockhash: true,\n sigVerify: false,\n })\n .send({ abortSignal: signal });\n\n const simulationValue: EnhancedSimulateTransactionValue = simulation.value;\n\n if (simulationValue.err) {\n // NOTE:\n // If `simulationValue.err` is not `null`, it means the transaction would fail if sent to the network.\n // You'll still get back fee and balance change information from the simulation response,\n // but it's inaccurate because it only covers the pre-failed instructions and doesn't account\n // for any instructions from the failed one onwards.\n //\n // This is why it's safest to just throw an error in this case.\n // If you there is a simulation error, no transaction is going to go through anyways.\n\n const errorDetails = mapTransactionErrorToEstimateNativeFeeErrorDetails(simulationValue.err);\n const [isInsufficientFundsError, isNativeFundsIssue] = isErrorInsufficientFunds(errorDetails, simulationValue.logs);\n\n let cause;\n\n if (isInsufficientFundsError) {\n cause = new InsufficientFundsError({\n errorCode: ErrorCode.SOLANA_ERROR,\n insufficientTokenWasNative: isNativeFundsIssue,\n details: `Simulation failed due to insufficient funds${isNativeFundsIssue ? ' for fee' : ''}.`,\n });\n }\n\n throw new EstimateNativeFeeError({\n cause,\n details: errorDetails,\n errorCode: ErrorCode.SOLANA_ERROR,\n tx: refreshedBase64EncodedWireTransaction,\n });\n }\n\n const decodedTransaction = decodeSolanaBase64Transaction(refreshedBase64EncodedWireTransaction);\n\n const signatureCount: bigint = getSignaturesCountFromDecodedTransaction(decodedTransaction);\n\n const baseFeeLamports: bigint = signatureCount * SOLANA_BASE_FEE_PER_SIGNATURE_LAMPORTS;\n const { computeUnitLimit, computeUnitPriceMicroLamports } = getComputeUnitBudgetPriceAndLimit(decodedTransaction);\n const priorityFeeLamports: bigint = calculatePriorityFeeLamports(computeUnitLimit, computeUnitPriceMicroLamports);\n\n const networkFeeLamports: bigint = simulationValue.fee ?? baseFeeLamports + priorityFeeLamports;\n const unitsConsumed: bigint = simulationValue.unitsConsumed == null ? 0n : simulationValue.unitsConsumed;\n\n const preBalances: readonly bigint[] = simulationValue.preBalances ?? [];\n const postBalances: readonly bigint[] = simulationValue.postBalances ?? [];\n const feePayerPreBalance = preBalances[SOLANA_FEE_PAYER_INDEX] ?? 0n;\n const feePayerPostBalance = postBalances[SOLANA_FEE_PAYER_INDEX] ?? 0n;\n\n const feePayerBalanceDiffLamports = feePayerPreBalance - feePayerPostBalance;\n\n return {\n baseFeeLamports,\n computeUnitLimit,\n computeUnitPriceMicroLamports,\n feePayerBalanceDiffLamports,\n networkFeeLamports,\n priorityFeeLamports,\n unitsConsumed,\n };\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n decodedTx: DecodedSolanaTransaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(decodedTx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const decodedTransaction = decodeSolanaBase64Transaction(swapTransactionBase64);\n\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(decodedTransaction, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{ErrorCode as e,EstimateNativeFeeError as t,InsufficientFundsError as n,SdkError as r}from"../errors.js";import{compileTransaction as i,decompileTransactionMessageFetchingLookupTables as a,getBase64EncodedWireTransaction as o,getBase64Encoder as s,getCompiledTransactionMessageDecoder as c,getTransactionDecoder as l,setTransactionMessageLifetimeUsingBlockhash as u}from"@solana/kit";const d=1000000n;function f(e){let t=s().encode(e);return l().decode(t)}function p(t){try{s().encode(t)}catch(t){throw new r(`Unable to decode transaction`,e.INVALID_PARAMS,{cause:t,details:`Unable to decode base64 transaction into Base64EncodedWireTransaction`})}}function m(e){if(typeof e==`string`)return{errorName:e};let t=Object.entries(e)[0];if(!t)return{errorName:`Unknown`,reason:`Unable to map Solana transaction error to details - no error information found`};let[n,r]=t;return{errorName:n,args:Array.isArray(r)?r:[r]}}function h(e,t){if(e.errorName===`InsufficientFundsForFee`||e.errorName===`InsufficientFundsForRent`)return[!0,!0];if(e.errorName===`InstructionError`&&e.args&&e.args[1]===`InsufficientFunds`)return[!0,!1];if(t){for(let e of t)if(/insufficient lamports/i.test(e))return[!0,!0]}return[!1,!1]}function g(e){return BigInt(Object.keys(e.signatures).length)}function _(e){let t=c().decode(e.messageBytes),n=0n,r=0n,i=e=>{if(e.length<1)return;let t=e[0],i=new DataView(e.buffer,e.byteOffset,e.byteLength);if(t===2&&e.length>=5){n=BigInt(i.getUint32(1,!0));return}t===3&&e.length>=9&&(r=i.getBigUint64(1,!0))};if(t.version===1){let e=Math.min(t.numInstructions,t.instructionHeaders.length,t.instructionPayloads.length);for(let n=0;n<e;n++){let e=t.instructionHeaders[n],r=t.instructionPayloads[n];!e||!r||t.staticAccounts[e.programAccountIndex]===`ComputeBudget111111111111111111111111111111`&&i(r.instructionData)}return{computeUnitLimit:n,computeUnitPriceMicroLamports:r}}for(let e of t.instructions){if(t.staticAccounts[e.programAddressIndex]!==`ComputeBudget111111111111111111111111111111`)continue;let n=e.data;n&&i(n)}return{computeUnitLimit:n,computeUnitPriceMicroLamports:r}}function v(e,t){return e<=0n||t<=0n?0n:(e*t+(d-1n))/d}async function y(r,i,{signal:a}={}){p(i);let o=await x(i,r),s=(await r.simulateTransaction(o,{encoding:`base64`,innerInstructions:!0,replaceRecentBlockhash:!0,sigVerify:!1}).send({abortSignal:a})).value;if(s.err){let r=m(s.err),[i,a]=h(r,s.logs),c;throw i&&(c=new n({errorCode:e.SOLANA_ERROR,insufficientTokenWasNative:a,details:`Simulation failed due to insufficient funds${a?` for fee`:``}.`})),new t({cause:c,details:r,errorCode:e.SOLANA_ERROR,tx:o})}let c=f(o),l=g(c)*5000n,{computeUnitLimit:u,computeUnitPriceMicroLamports:d}=_(c),y=v(u,d),b=s.fee??l+y,S=s.unitsConsumed==null?0n:s.unitsConsumed,C=s.preBalances??[],w=s.postBalances??[];return{baseFeeLamports:l,computeUnitLimit:u,computeUnitPriceMicroLamports:d,feePayerBalanceDiffLamports:(C[0]??0n)-(w[0]??0n),networkFeeLamports:b,priorityFeeLamports:y,unitsConsumed:S}}async function b(e,t){return await a(c().decode(e.messageBytes),t)}async function x(e,t){let n=f(e),[r,a]=await Promise.all([b(n,t),t.getLatestBlockhash().send()]);return o(i(u(a.value,r)))}export{y as estimateSolanaFee,x as refreshSolanaSwapTransactionBlockhash};
2
+ //# sourceMappingURL=solana.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.js","names":[],"sources":["../../src/utils/solana.ts"],"sourcesContent":["import {\n compileTransaction,\n createSolanaRpc,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getBase64Encoder,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SignaturesMap,\n type SolanaRpcApi,\n type TransactionError,\n type TransactionMessageBytes,\n} from '@solana/kit';\nimport { splitCaip2ChainId } from './caip';\nimport {\n ErrorCode,\n EstimateNativeFeeError,\n InsufficientFundsError,\n InvalidParamsError,\n SdkError,\n type EstimateNativeFeeErrorDetails,\n} from '../errors';\nimport type { Chain } from '../types/chain';\n\n/** Index of the fee payer in a Solana transaction. */\nexport const SOLANA_FEE_PAYER_INDEX = 0;\n\n/**\n * Compute Budget program address.\n *\n * Used to detect `SetComputeUnitPrice` instructions when deriving\n * the Solana priority fee component from transaction message bytes.\n */\nexport const SOLANA_COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';\n\n/**\n * System Program address.\n *\n * Used to detect account-creation instructions and extract lamports\n * funded upfront for newly created system accounts.\n */\nexport const SOLANA_SYSTEM_PROGRAM = '11111111111111111111111111111111';\n\n/**\n * Associated Token Account (ATA) program address.\n *\n * Used to detect ATA create instructions so the estimator can include\n * rent-exempt funding when the ATA does not already exist on-chain.\n */\nexport const SOLANA_ASSOCIATED_TOKEN_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';\n\n/**\n * Legacy SPL Token program address.\n *\n * Used to detect close-account instructions that may refund lamports\n * from temporary token accounts back to the sender.\n */\nexport const SOLANA_SPL_TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';\n\n/**\n * SPL Token-2022 program address.\n *\n * Used alongside the legacy token program for close-account detection\n * when computing expected refundable lamports.\n */\nexport const SOLANA_SPL_TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';\n\n/**\n * SPL token account size for rent-exemption calculations.\n *\n * Used with `getMinimumBalanceForRentExemption` to estimate ATA\n * creation funding requirements.\n */\nexport const SPL_TOKEN_ACCOUNT_SIZE_BYTES = 165n;\nexport const SOLANA_BASE_FEE_PER_SIGNATURE_LAMPORTS = 5_000n;\nexport const MICRO_LAMPORTS_PER_LAMPORT = 1_000_000n;\n\n/**\n * Creates a Solana RPC client for the given chain.\n *\n * @param chain - The chain for which to create the Solana RPC client. Must be a Solana chain.\n * @returns A Solana RPC client instance.\n * @throws {InvalidParamsError} If the provided chain is not a Solana chain.\n */\nexport function getSolanaRpcForChain(chain: Chain): Rpc<SolanaRpcApi> {\n const { namespace } = splitCaip2ChainId(chain.chainId);\n\n if (namespace !== 'solana') {\n throw new InvalidParamsError('Can not create Solana RPC', 'Provided chain is not a Solana chain');\n }\n\n return createSolanaRpc(chain.rpcUrl);\n}\n\n/**\n * Decoded representation of a Solana transaction, including the message bytes and signatures.\n */\nexport type DecodedSolanaTransaction = Readonly<{ messageBytes: TransactionMessageBytes; signatures: SignaturesMap }>;\n\n/**\n * Decodes a base64-encoded Solana transaction into its message bytes and signatures.\n *\n * @param base64Tx - The base64-encoded Solana transaction string.\n * @returns An object containing the decoded message bytes and signatures.\n * @throws {Error} If the transaction cannot be decoded.\n */\nexport function decodeSolanaBase64Transaction(base64Tx: string): DecodedSolanaTransaction {\n const base64Encoder = getBase64Encoder();\n const transactionBytes = base64Encoder.encode(base64Tx);\n\n const transactionDecoder = getTransactionDecoder();\n\n return transactionDecoder.decode(transactionBytes);\n}\n\n/**\n * Encodes a decoded Solana transaction (message bytes and signatures) into\n * a base64-encoded string suitable for sending via RPC.\n *\n * @param transaction - The decoded Solana transaction containing message bytes and signatures.\n * @returns A base64-encoded string representing the Solana transaction.\n * @throws {Error} If the transaction cannot be encoded.\n */\nexport function encodeSolanaTransactionToBase64(transaction: DecodedSolanaTransaction): Base64EncodedWireTransaction {\n return getBase64EncodedWireTransaction(transaction);\n}\n\n/**\n * Asserts that a given string is a valid base64-encoded Solana transaction.\n *\n * @param base64Tx - The string to validate as a base64-encoded Solana transaction.\n * @throws {SdkError} If the string is not a valid base64-encoded Solana transaction.\n */\nexport function assertSolanaBase64Transaction(base64Tx: string): asserts base64Tx is Base64EncodedWireTransaction {\n try {\n const base64Encoder = getBase64Encoder();\n base64Encoder.encode(base64Tx);\n } catch (error) {\n throw new SdkError('Unable to decode transaction', ErrorCode.INVALID_PARAMS, {\n cause: error,\n details: 'Unable to decode base64 transaction into Base64EncodedWireTransaction',\n });\n }\n}\n\ntype ExtractTransactionErrorString<T extends TransactionError> = T extends string ? T : keyof T;\n\ntype TransactionErrorString = ExtractTransactionErrorString<TransactionError> | 'Unknown';\n\ninterface EstimateNativeFeeErrorDetailsWithRequiredErrorName extends EstimateNativeFeeErrorDetails {\n errorName: TransactionErrorString;\n}\n\nexport function mapTransactionErrorToEstimateNativeFeeErrorDetails(\n err: TransactionError,\n): EstimateNativeFeeErrorDetailsWithRequiredErrorName {\n if (typeof err === 'string') {\n return { errorName: err };\n }\n\n const errorEntries = Object.entries(err);\n\n const error = errorEntries[0];\n\n if (!error) {\n return {\n errorName: 'Unknown',\n reason: 'Unable to map Solana transaction error to details - no error information found',\n };\n }\n\n const [errorName, errorArgs] = error;\n\n return {\n errorName: errorName as TransactionErrorString,\n args: Array.isArray(errorArgs) ? errorArgs : [errorArgs],\n };\n}\n\nfunction isErrorInsufficientFunds(\n errorDetails: EstimateNativeFeeErrorDetailsWithRequiredErrorName,\n logs?: readonly string[] | null,\n): [isInsufficientFundsError: boolean, isNativeFundsIssue: boolean] {\n if (errorDetails.errorName === 'InsufficientFundsForFee' || errorDetails.errorName === 'InsufficientFundsForRent') {\n return [true, true];\n }\n\n if (\n errorDetails.errorName === 'InstructionError' &&\n errorDetails.args &&\n errorDetails.args[1] === 'InsufficientFunds'\n ) {\n return [true, false];\n }\n\n if (logs) {\n // Look for /insufficient lamports/ error in logs, if found return [true, true].\n for (const log of logs) {\n if (/insufficient lamports/i.test(log)) {\n return [true, true];\n }\n }\n }\n\n return [false, false];\n}\n\nexport function getSignaturesCountFromDecodedTransaction(decodedTransaction: DecodedSolanaTransaction): bigint {\n return BigInt(Object.keys(decodedTransaction.signatures).length);\n}\n\nexport function getComputeUnitBudgetPriceAndLimit(decodedTransaction: DecodedSolanaTransaction): {\n computeUnitLimit: bigint;\n computeUnitPriceMicroLamports: bigint;\n} {\n type TransactionInstructionData = {\n readonly [index: number]: number;\n readonly buffer: ArrayBufferLike;\n readonly byteLength: number;\n readonly byteOffset: number;\n readonly length: number;\n };\n\n const compiledTxMessage = getCompiledTransactionMessageDecoder().decode(decodedTransaction.messageBytes);\n let computeUnitLimit = 0n;\n let computeUnitPriceMicroLamports = 0n;\n\n const updateBudgetValuesFromData = (data: TransactionInstructionData): void => {\n if (data.length < 1) {\n return;\n }\n\n const discriminator = data[0];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // ComputeBudget::SetComputeUnitLimit(u32)\n if (discriminator === 2 && data.length >= 1 + 4) {\n computeUnitLimit = BigInt(view.getUint32(1, true));\n return;\n }\n\n // ComputeBudget::SetComputeUnitPrice(u64)\n if (discriminator === 3 && data.length >= 1 + 8) {\n computeUnitPriceMicroLamports = view.getBigUint64(1, true);\n }\n };\n\n if (compiledTxMessage.version === 1) {\n const maxInstructionCount = Math.min(\n compiledTxMessage.numInstructions,\n compiledTxMessage.instructionHeaders.length,\n compiledTxMessage.instructionPayloads.length,\n );\n\n for (let instructionIndex = 0; instructionIndex < maxInstructionCount; instructionIndex++) {\n const instructionHeader = compiledTxMessage.instructionHeaders[instructionIndex];\n const instructionPayload = compiledTxMessage.instructionPayloads[instructionIndex];\n if (!instructionHeader || !instructionPayload) {\n continue;\n }\n\n const programAddress = compiledTxMessage.staticAccounts[instructionHeader.programAccountIndex];\n if (programAddress !== SOLANA_COMPUTE_BUDGET_PROGRAM) {\n continue;\n }\n\n updateBudgetValuesFromData(instructionPayload.instructionData);\n }\n\n return { computeUnitLimit, computeUnitPriceMicroLamports };\n }\n\n for (const instruction of compiledTxMessage.instructions) {\n const programAddress = compiledTxMessage.staticAccounts[instruction.programAddressIndex];\n if (programAddress !== SOLANA_COMPUTE_BUDGET_PROGRAM) {\n continue;\n }\n\n const data = instruction.data;\n if (!data) {\n continue;\n }\n\n updateBudgetValuesFromData(data);\n }\n\n return { computeUnitLimit, computeUnitPriceMicroLamports };\n}\n\nexport function calculatePriorityFeeLamports(computeUnitLimit: bigint, computeUnitPriceMicroLamports: bigint): bigint {\n if (computeUnitLimit <= 0n || computeUnitPriceMicroLamports <= 0n) {\n return 0n;\n }\n\n return (\n (computeUnitLimit * computeUnitPriceMicroLamports + (MICRO_LAMPORTS_PER_LAMPORT - 1n)) / MICRO_LAMPORTS_PER_LAMPORT\n );\n}\n\ntype SimulateTransactionBaseValue = Awaited<\n ReturnType<ReturnType<Rpc<SolanaRpcApi>['simulateTransaction']>['send']>\n>['value'];\n\ninterface SimulateTransactionRuntimeExtras {\n readonly fee?: bigint;\n readonly preBalances?: readonly bigint[];\n readonly postBalances?: readonly bigint[];\n // readonly preTokenBalances?: readonly unknown[];\n // readonly postTokenBalances?: readonly unknown[];\n readonly loadedAddresses?: Readonly<{\n readonly readonly: readonly string[];\n readonly writable: readonly string[];\n }>;\n // readonly innerInstructions?: readonly unknown[] | null;\n}\n\ntype EnhancedSimulateTransactionValue = SimulateTransactionBaseValue & SimulateTransactionRuntimeExtras;\n\nexport async function estimateSolanaFee(\n rpc: Rpc<SolanaRpcApi>,\n base64EncodedWireTransaction: string,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<\n Readonly<{\n baseFeeLamports: bigint;\n computeUnitLimit: bigint;\n computeUnitPriceMicroLamports: bigint;\n /**\n * Total consumed lamports for transaction.\n *\n * If transaction swap input amount was in native SOL,\n * subtract the total input value (input amount + additive fee SOL) from\n * this value to get the total fee cost for the transaction.\n */\n feePayerBalanceDiffLamports: bigint;\n /** The sum of base fee and priority fee */\n networkFeeLamports: bigint;\n priorityFeeLamports: bigint;\n unitsConsumed: bigint;\n }>\n> {\n assertSolanaBase64Transaction(base64EncodedWireTransaction);\n const refreshedBase64EncodedWireTransaction = await refreshSolanaSwapTransactionBlockhash(\n base64EncodedWireTransaction,\n rpc,\n );\n\n const simulation = await rpc\n .simulateTransaction(refreshedBase64EncodedWireTransaction, {\n encoding: 'base64',\n innerInstructions: true,\n replaceRecentBlockhash: true,\n sigVerify: false,\n })\n .send({ abortSignal: signal });\n\n const simulationValue: EnhancedSimulateTransactionValue = simulation.value;\n\n if (simulationValue.err) {\n // NOTE:\n // If `simulationValue.err` is not `null`, it means the transaction would fail if sent to the network.\n // You'll still get back fee and balance change information from the simulation response,\n // but it's inaccurate because it only covers the pre-failed instructions and doesn't account\n // for any instructions from the failed one onwards.\n //\n // This is why it's safest to just throw an error in this case.\n // If you there is a simulation error, no transaction is going to go through anyways.\n\n const errorDetails = mapTransactionErrorToEstimateNativeFeeErrorDetails(simulationValue.err);\n const [isInsufficientFundsError, isNativeFundsIssue] = isErrorInsufficientFunds(errorDetails, simulationValue.logs);\n\n let cause;\n\n if (isInsufficientFundsError) {\n cause = new InsufficientFundsError({\n errorCode: ErrorCode.SOLANA_ERROR,\n insufficientTokenWasNative: isNativeFundsIssue,\n details: `Simulation failed due to insufficient funds${isNativeFundsIssue ? ' for fee' : ''}.`,\n });\n }\n\n throw new EstimateNativeFeeError({\n cause,\n details: errorDetails,\n errorCode: ErrorCode.SOLANA_ERROR,\n tx: refreshedBase64EncodedWireTransaction,\n });\n }\n\n const decodedTransaction = decodeSolanaBase64Transaction(refreshedBase64EncodedWireTransaction);\n\n const signatureCount: bigint = getSignaturesCountFromDecodedTransaction(decodedTransaction);\n\n const baseFeeLamports: bigint = signatureCount * SOLANA_BASE_FEE_PER_SIGNATURE_LAMPORTS;\n const { computeUnitLimit, computeUnitPriceMicroLamports } = getComputeUnitBudgetPriceAndLimit(decodedTransaction);\n const priorityFeeLamports: bigint = calculatePriorityFeeLamports(computeUnitLimit, computeUnitPriceMicroLamports);\n\n const networkFeeLamports: bigint = simulationValue.fee ?? baseFeeLamports + priorityFeeLamports;\n const unitsConsumed: bigint = simulationValue.unitsConsumed == null ? 0n : simulationValue.unitsConsumed;\n\n const preBalances: readonly bigint[] = simulationValue.preBalances ?? [];\n const postBalances: readonly bigint[] = simulationValue.postBalances ?? [];\n const feePayerPreBalance = preBalances[SOLANA_FEE_PAYER_INDEX] ?? 0n;\n const feePayerPostBalance = postBalances[SOLANA_FEE_PAYER_INDEX] ?? 0n;\n\n const feePayerBalanceDiffLamports = feePayerPreBalance - feePayerPostBalance;\n\n return {\n baseFeeLamports,\n computeUnitLimit,\n computeUnitPriceMicroLamports,\n feePayerBalanceDiffLamports,\n networkFeeLamports,\n priorityFeeLamports,\n unitsConsumed,\n };\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n decodedTx: DecodedSolanaTransaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(decodedTx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const decodedTransaction = decodeSolanaBase64Transaction(swapTransactionBase64);\n\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(decodedTransaction, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@avalabs/fusion-sdk",
3
3
  "license": "Limited Ecosystem License",
4
- "version": "0.14.4",
4
+ "version": "0.15.1",
5
5
  "type": "module",
6
6
  "main": "./dist/mod.cjs",
7
7
  "module": "./dist/mod.js",
@@ -35,20 +35,20 @@
35
35
  "es-toolkit": "^1.42.0"
36
36
  },
37
37
  "peerDependencies": {
38
- "@solana/kit": "^5.0.0",
38
+ "@solana/kit": "^5.0.0 || ^6.0.0",
39
39
  "viem": "^2.38.0",
40
40
  "zod": "^4.1.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@solana/kit": "5.0.0",
43
+ "@solana/kit": "6.5.0",
44
44
  "@vitest/coverage-v8": "4.0.6",
45
45
  "publint": "0.3.17",
46
46
  "viem": "2.38.3",
47
47
  "vitest": "4.0.6",
48
- "tsdown": "0.20.3",
48
+ "tsdown": "0.21.4",
49
49
  "zod": "4.1.12",
50
- "@internal/tsdown-config": "0.0.1",
51
- "eslint-config-custom": "0.1.0"
50
+ "eslint-config-custom": "0.1.0",
51
+ "@internal/tsdown-config": "0.0.1"
52
52
  },
53
53
  "sideEffects": false,
54
54
  "scripts": {
@@ -1,2 +0,0 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../errors.cjs`);let t=require(`zod`);require(`viem`);let n=require(`@solana/kit`);const r=t.z.base64();function i(t){if(!r.safeParse(t).success)throw new e.InvalidParamsError(`Not a valid base64 string`,`Expected a base64-encoded Solana Transaction string.`);let i=Uint8Array.from(atob(t),e=>e.charCodeAt(0)),a;try{a=(0,n.getTransactionDecoder)().decode(i)}catch(t){throw new e.SdkError(`Failed to decode transaction.`,e.ErrorCode.SOLANA_ERROR,{cause:t})}return a}async function a(e,t){return await(0,n.decompileTransactionMessageFetchingLookupTables)((0,n.getCompiledTransactionMessageDecoder)().decode(e.messageBytes),t)}async function o(e,t){let r=i(e),[o,s]=await Promise.all([a(r,t),t.getLatestBlockhash().send()]);return(0,n.getBase64EncodedWireTransaction)((0,n.compileTransaction)((0,n.setTransactionMessageLifetimeUsingBlockhash)(s.value,o)))}exports.decodeSolanaTransactionBase64=i,exports.refreshSolanaSwapTransactionBlockhash=o;
2
- //# sourceMappingURL=_solana-utils.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_solana-utils.cjs","names":["z","InvalidParamsError","SdkError","ErrorCode"],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { bytesToHex, bytesToString } from 'viem';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\nexport interface DecodedSolanaInstructionDebug {\n index: number;\n programAddressIndex: number;\n programAddress: string | undefined;\n accountIndices: number[];\n accountAddresses: Array<string | undefined>;\n dataBase64: string;\n dataHex: string;\n}\n\nfunction _bytesToBase64(bytes: Uint8Array): string {\n return btoa(bytesToString(bytes));\n}\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Returns a normalized, readable instruction list from a base64 Solana transaction.\n *\n * This is intended for debugging and inspection. Account addresses are resolved\n * from the decoded message static account list when available.\n */\nexport function decodeSolanaInstructionListFromSwapTransactionBase64(\n swapTransactionBase64: string,\n): DecodedSolanaInstructionDebug[] {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return compiledMessage.instructions.map((instruction, index) => {\n const accountIndices = instruction.accountIndices ? [...instruction.accountIndices] : [];\n const data = instruction.data ? new Uint8Array(instruction.data) : new Uint8Array();\n\n return {\n index,\n programAddressIndex: instruction.programAddressIndex,\n programAddress: compiledMessage.staticAccounts[instruction.programAddressIndex],\n accountIndices,\n accountAddresses: accountIndices.map((accountIndex) => compiledMessage.staticAccounts[accountIndex]),\n dataBase64: _bytesToBase64(data),\n dataHex: bytesToHex(data),\n };\n });\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"sJAgBA,MAAM,EAAoCA,EAAAA,EAAE,QAAQ,CAsBpD,SAAgB,EAA8B,EAA4C,CAGxF,GAAI,CAFiB,EAAkC,UAAU,EAAsB,CAErE,QAChB,MAAM,IAAIC,EAAAA,mBAAmB,4BAA6B,uDAAuD,CAGnH,IAAM,EAAU,WAAW,KAAK,KAAK,EAAsB,CAAG,GAAc,EAAU,WAAW,EAAE,CAAC,CAEhG,EAEJ,GAAI,CACF,GAAA,EAAA,EAAA,wBAA4B,CAAC,OAAO,EAAQ,OACrC,EAAO,CACd,MAAM,IAAIC,EAAAA,SAAS,gCAAiCC,EAAAA,UAAU,aAAc,CAAE,MAAO,EAAO,CAAC,CAG/F,OAAO,EAqCT,eAAsB,EACpB,EACA,EAC6E,CAG7E,OAAO,MAAA,EAAA,EAAA,kDAAA,EAAA,EAAA,uCAFmE,CAAC,OAAO,EAAG,aAAa,CAER,EAAI,CAShG,eAAsB,EACpB,EACA,EACuC,CACvC,IAAM,EAAK,EAA8B,EAAsB,CACzD,CAAC,EAAmB,GAA2B,MAAM,QAAQ,IAAI,CACrE,EAAoC,EAAI,EAAI,CAC5C,EAAI,oBAAoB,CAAC,MAAM,CAChC,CAAC,CASF,OAAA,EAAA,EAAA,kCAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,6CANE,EAAwB,MACxB,EACD,CAEyD,CAEP"}
@@ -1,2 +0,0 @@
1
- import{ErrorCode as e,InvalidParamsError as t,SdkError as n}from"../../errors.js";import{z as r}from"zod";import"viem";import{compileTransaction as i,decompileTransactionMessageFetchingLookupTables as a,getBase64EncodedWireTransaction as o,getCompiledTransactionMessageDecoder as s,getTransactionDecoder as c,setTransactionMessageLifetimeUsingBlockhash as l}from"@solana/kit";const u=r.base64();function d(r){if(!u.safeParse(r).success)throw new t(`Not a valid base64 string`,`Expected a base64-encoded Solana Transaction string.`);let i=Uint8Array.from(atob(r),e=>e.charCodeAt(0)),a;try{a=c().decode(i)}catch(t){throw new n(`Failed to decode transaction.`,e.SOLANA_ERROR,{cause:t})}return a}async function f(e,t){return await a(s().decode(e.messageBytes),t)}async function p(e,t){let n=d(e),[r,a]=await Promise.all([f(n,t),t.getLatestBlockhash().send()]);return o(i(l(a.value,r)))}export{d as decodeSolanaTransactionBase64,p as refreshSolanaSwapTransactionBlockhash};
2
- //# sourceMappingURL=_solana-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_solana-utils.js","names":[],"sources":["../../../src/transfer-service/markr/_solana-utils.ts"],"sourcesContent":["import {\n compileTransaction,\n decompileTransactionMessageFetchingLookupTables,\n getBase64EncodedWireTransaction,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n setTransactionMessageLifetimeUsingBlockhash,\n type Base64EncodedWireTransaction,\n type Rpc,\n type SolanaRpcApi,\n type Transaction,\n} from '@solana/kit';\nimport { bytesToHex, bytesToString } from 'viem';\nimport { z } from 'zod';\nimport { ErrorCode, InvalidParamsError, SdkError } from '../../errors';\n\nconst SolanaSwapTransactionBase64Schema = z.base64();\n\nexport interface DecodedSolanaInstructionDebug {\n index: number;\n programAddressIndex: number;\n programAddress: string | undefined;\n accountIndices: number[];\n accountAddresses: Array<string | undefined>;\n dataBase64: string;\n dataHex: string;\n}\n\nfunction _bytesToBase64(bytes: Uint8Array): string {\n return btoa(bytesToString(bytes));\n}\n\n/**\n * Decodes a base64-encoded serialized Solana transaction.\n *\n * Validates that the input is base64 before attempting to deserialize.\n * Throws SDK errors with stable codes so callers can map failures.\n */\nexport function decodeSolanaTransactionBase64(swapTransactionBase64: string): Transaction {\n const parsedBase64 = SolanaSwapTransactionBase64Schema.safeParse(swapTransactionBase64);\n\n if (!parsedBase64.success) {\n throw new InvalidParamsError('Not a valid base64 string', 'Expected a base64-encoded Solana Transaction string.');\n }\n\n const txBytes = Uint8Array.from(atob(swapTransactionBase64), (character) => character.charCodeAt(0));\n\n let tx: Transaction;\n\n try {\n tx = getTransactionDecoder().decode(txBytes);\n } catch (error) {\n throw new SdkError('Failed to decode transaction.', ErrorCode.SOLANA_ERROR, { cause: error });\n }\n\n return tx;\n}\n\n/**\n * Returns a normalized, readable instruction list from a base64 Solana transaction.\n *\n * This is intended for debugging and inspection. Account addresses are resolved\n * from the decoded message static account list when available.\n */\nexport function decodeSolanaInstructionListFromSwapTransactionBase64(\n swapTransactionBase64: string,\n): DecodedSolanaInstructionDebug[] {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return compiledMessage.instructions.map((instruction, index) => {\n const accountIndices = instruction.accountIndices ? [...instruction.accountIndices] : [];\n const data = instruction.data ? new Uint8Array(instruction.data) : new Uint8Array();\n\n return {\n index,\n programAddressIndex: instruction.programAddressIndex,\n programAddress: compiledMessage.staticAccounts[instruction.programAddressIndex],\n accountIndices,\n accountAddresses: accountIndices.map((accountIndex) => compiledMessage.staticAccounts[accountIndex]),\n dataBase64: _bytesToBase64(data),\n dataHex: bytesToHex(data),\n };\n });\n}\n\n/**\n * Decompiles a transaction message, resolving address lookup tables via RPC.\n *\n * This returns a message shape that can be mutated (for example, to refresh\n * blockhash lifetime) and recompiled into a new transaction.\n */\nexport async function getDecompiledMessageFromTransaction(\n tx: Transaction,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<ReturnType<typeof decompileTransactionMessageFetchingLookupTables>> {\n const compiledMessageWithLifetime = getCompiledTransactionMessageDecoder().decode(tx.messageBytes);\n\n return await decompileTransactionMessageFetchingLookupTables(compiledMessageWithLifetime, rpc);\n}\n\n/**\n * Refreshes a serialized Solana swap transaction to use the latest blockhash.\n *\n * The returned value is a base64-encoded serialized transaction suitable for\n * signing and broadcast.\n */\nexport async function refreshSolanaSwapTransactionBlockhash(\n swapTransactionBase64: string,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Base64EncodedWireTransaction> {\n const tx = decodeSolanaTransactionBase64(swapTransactionBase64);\n const [decompiledMessage, latestBlockhashResponse] = await Promise.all([\n getDecompiledMessageFromTransaction(tx, rpc),\n rpc.getLatestBlockhash().send(),\n ]);\n\n const refreshedTxMessage = setTransactionMessageLifetimeUsingBlockhash(\n latestBlockhashResponse.value,\n decompiledMessage,\n );\n\n const refreshedTx = compileTransaction(refreshedTxMessage);\n\n return getBase64EncodedWireTransaction(refreshedTx);\n}\n"],"mappings":"wXAgBA,MAAM,EAAoC,EAAE,QAAQ,CAsBpD,SAAgB,EAA8B,EAA4C,CAGxF,GAAI,CAFiB,EAAkC,UAAU,EAAsB,CAErE,QAChB,MAAM,IAAI,EAAmB,4BAA6B,uDAAuD,CAGnH,IAAM,EAAU,WAAW,KAAK,KAAK,EAAsB,CAAG,GAAc,EAAU,WAAW,EAAE,CAAC,CAEhG,EAEJ,GAAI,CACF,EAAK,GAAuB,CAAC,OAAO,EAAQ,OACrC,EAAO,CACd,MAAM,IAAI,EAAS,gCAAiC,EAAU,aAAc,CAAE,MAAO,EAAO,CAAC,CAG/F,OAAO,EAqCT,eAAsB,EACpB,EACA,EAC6E,CAG7E,OAAO,MAAM,EAFuB,GAAsC,CAAC,OAAO,EAAG,aAAa,CAER,EAAI,CAShG,eAAsB,EACpB,EACA,EACuC,CACvC,IAAM,EAAK,EAA8B,EAAsB,CACzD,CAAC,EAAmB,GAA2B,MAAM,QAAQ,IAAI,CACrE,EAAoC,EAAI,EAAI,CAC5C,EAAI,oBAAoB,CAAC,MAAM,CAChC,CAAC,CASF,OAAO,EAFa,EALO,EACzB,EAAwB,MACxB,EACD,CAEyD,CAEP"}