@vultisig/core-chain 2.17.11 → 2.19.0
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.
- package/CHANGELOG.md +35 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcGovParams.d.ts +8 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcGovParams.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcGovParams.js +31 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcGovParams.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcMyVote.d.ts +12 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcMyVote.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcMyVote.js +32 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcMyVote.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposalTally.d.ts +4 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposalTally.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposalTally.js +8 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposalTally.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposals.d.ts +7 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposals.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposals.js +13 -0
- package/dist/chains/cosmos/qbtc/governance/getQbtcProposals.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/parseGov.d.ts +26 -0
- package/dist/chains/cosmos/qbtc/governance/parseGov.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/parseGov.js +46 -0
- package/dist/chains/cosmos/qbtc/governance/parseGov.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/proposal.d.ts +64 -0
- package/dist/chains/cosmos/qbtc/governance/proposal.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/proposal.js +39 -0
- package/dist/chains/cosmos/qbtc/governance/proposal.js.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/voteOption.d.ts +17 -0
- package/dist/chains/cosmos/qbtc/governance/voteOption.d.ts.map +1 -0
- package/dist/chains/cosmos/qbtc/governance/voteOption.js +38 -0
- package/dist/chains/cosmos/qbtc/governance/voteOption.js.map +1 -0
- package/dist/chains/ton/address.d.ts +9 -0
- package/dist/chains/ton/address.d.ts.map +1 -1
- package/dist/chains/ton/address.js +13 -0
- package/dist/chains/ton/address.js.map +1 -1
- package/dist/chains/ton/staking.d.ts +104 -0
- package/dist/chains/ton/staking.d.ts.map +1 -0
- package/dist/chains/ton/staking.js +137 -0
- package/dist/chains/ton/staking.js.map +1 -0
- package/dist/coin/balance/getEvmChainBalances.d.ts +11 -0
- package/dist/coin/balance/getEvmChainBalances.d.ts.map +1 -0
- package/dist/coin/balance/getEvmChainBalances.js +57 -0
- package/dist/coin/balance/getEvmChainBalances.js.map +1 -0
- package/dist/swap/general/GeneralSwapProvider.d.ts +1 -1
- package/dist/swap/general/GeneralSwapProvider.d.ts.map +1 -1
- package/dist/swap/general/GeneralSwapProvider.js +2 -1
- package/dist/swap/general/GeneralSwapProvider.js.map +1 -1
- package/dist/swap/general/jupiter/JupiterSwapEnabledChains.d.ts +9 -0
- package/dist/swap/general/jupiter/JupiterSwapEnabledChains.d.ts.map +1 -0
- package/dist/swap/general/jupiter/JupiterSwapEnabledChains.js +9 -0
- package/dist/swap/general/jupiter/JupiterSwapEnabledChains.js.map +1 -0
- package/dist/swap/general/jupiter/api/getJupiterSwapQuote.d.ts +25 -0
- package/dist/swap/general/jupiter/api/getJupiterSwapQuote.d.ts.map +1 -0
- package/dist/swap/general/jupiter/api/getJupiterSwapQuote.js +112 -0
- package/dist/swap/general/jupiter/api/getJupiterSwapQuote.js.map +1 -0
- package/dist/swap/general/jupiter/api/jupiterFeeAta.d.ts +48 -0
- package/dist/swap/general/jupiter/api/jupiterFeeAta.d.ts.map +1 -0
- package/dist/swap/general/jupiter/api/jupiterFeeAta.js +115 -0
- package/dist/swap/general/jupiter/api/jupiterFeeAta.js.map +1 -0
- package/dist/swap/general/jupiter/config.d.ts +13 -0
- package/dist/swap/general/jupiter/config.d.ts.map +1 -0
- package/dist/swap/general/jupiter/config.js +52 -0
- package/dist/swap/general/jupiter/config.js.map +1 -0
- package/dist/swap/quote/findSwapQuote.d.ts +1 -1
- package/dist/swap/quote/findSwapQuote.d.ts.map +1 -1
- package/dist/swap/quote/findSwapQuote.js +33 -1
- package/dist/swap/quote/findSwapQuote.js.map +1 -1
- package/dist/swap/utils/getSwapExplorerUrl/index.d.ts +2 -2
- package/dist/swap/utils/getSwapExplorerUrl/index.d.ts.map +1 -1
- package/dist/swap/utils/getSwapExplorerUrl/index.js +11 -2
- package/dist/swap/utils/getSwapExplorerUrl/index.js.map +1 -1
- package/package.json +66 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staking.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/staking.ts"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,2BAA4B,CAAA;AAEpE,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAA;AAErF,eAAO,MAAM,4BAA4B,GACvC,gBAAgB,MAAM,GAAG,SAAS,KACjC,cAAc,IAAI,0BAC4E,CAAA;AAqBjG,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,GAAI,gBAAgB,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SACe,CAAA;AAEtG,oGAAoG;AACpG,eAAO,MAAM,yBAAyB,GAAI,gBAAgB,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SACe,CAAA;AAOvG;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,GAAG,SAAS,KAAG,OAAwD,CAAA;AAEvH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,cAAiB,CAAA;AAErD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,aAAe,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,YAAc,CAAA;AAc/C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAiBD,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,MAAM,cAAc,KAAG,OAMzD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,cAAc,KAAG,OACsC,CAAA;AAEhG;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,cAAc,EAAE,CAKnE,CAAA;AAWD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAavG,CAAA;AAUD;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,oBAAoB,EAAE,CAW5F,CAAA"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
|
|
2
|
+
import { tonAddressToBounceable } from './address.js';
|
|
3
|
+
/**
|
|
4
|
+
* Public TonAPI host. The staking endpoints (`/v2/staking/*`) are served
|
|
5
|
+
* exclusively by `tonapi.io` — the Vultisig `/ton` proxy fronts toncenter v3,
|
|
6
|
+
* which has no staking routes — so we hit tonapi.io directly. The extension's
|
|
7
|
+
* wildcard https host permission covers it.
|
|
8
|
+
*/
|
|
9
|
+
const tonApiPublicUrl = 'https://tonapi.io';
|
|
10
|
+
/**
|
|
11
|
+
* tonapi `implementation` values that are genuine **nominator pools** — the
|
|
12
|
+
* only ones the text-comment deposit/withdraw mechanism can stake into.
|
|
13
|
+
* `liquidTF` (Tonstakers) mints a jetton instead and is excluded; unknown
|
|
14
|
+
* implementations are treated as non-nominator (excluded).
|
|
15
|
+
*/
|
|
16
|
+
export const tonNominatorImplementations = ['whales', 'tf'];
|
|
17
|
+
export const isTonNominatorImplementation = (implementation) => !!implementation && tonNominatorImplementations.includes(implementation);
|
|
18
|
+
/**
|
|
19
|
+
* The deposit/withdraw text comments a TON nominator-pool contract expects.
|
|
20
|
+
* Each pool *implementation* uses a DIFFERENT word — sending the wrong one is
|
|
21
|
+
* rejected on-chain (exit code 72). These are contract protocol tokens, NOT
|
|
22
|
+
* user-facing UI: never translate them.
|
|
23
|
+
*
|
|
24
|
+
* The Whales pool repo README's "Stake" is stale and rejected by the live
|
|
25
|
+
* pools; the verified on-chain word is "Deposit".
|
|
26
|
+
*/
|
|
27
|
+
const tonStakingDepositComments = {
|
|
28
|
+
tf: 'd',
|
|
29
|
+
whales: 'Deposit',
|
|
30
|
+
};
|
|
31
|
+
const tonStakingWithdrawComments = {
|
|
32
|
+
tf: 'w',
|
|
33
|
+
whales: 'Withdraw',
|
|
34
|
+
};
|
|
35
|
+
/** Deposit comment for a pool implementation, or `undefined` if unsupported (block the action). */
|
|
36
|
+
export const tonStakingDepositComment = (implementation) => isTonNominatorImplementation(implementation) ? tonStakingDepositComments[implementation] : undefined;
|
|
37
|
+
/** Withdraw comment for a pool implementation, or `undefined` if unsupported (block the action). */
|
|
38
|
+
export const tonStakingWithdrawComment = (implementation) => isTonNominatorImplementation(implementation) ? tonStakingWithdrawComments[implementation] : undefined;
|
|
39
|
+
const tonStakingComments = new Set([
|
|
40
|
+
...Object.values(tonStakingDepositComments),
|
|
41
|
+
...Object.values(tonStakingWithdrawComments),
|
|
42
|
+
]);
|
|
43
|
+
/**
|
|
44
|
+
* Whether a memo is a nominator-pool deposit/withdraw comment (`d`/`w`/`Deposit`
|
|
45
|
+
* /`Withdraw`). The signer uses this to force the transfer bounceable: a pool
|
|
46
|
+
* deposit/withdraw sent non-bounceable can be absorbed (lost) by the pool
|
|
47
|
+
* instead of bounced back if rejected.
|
|
48
|
+
*/
|
|
49
|
+
export const isTonStakingComment = (memo) => !!memo && tonStakingComments.has(memo.trim());
|
|
50
|
+
/**
|
|
51
|
+
* Processing-commission buffer (nanotons) added on top of a pool's `min_stake`
|
|
52
|
+
* for the minimum acceptable deposit. Depositing exactly the minimum is
|
|
53
|
+
* rejected; the pool needs ~1 TON headroom for its processing commission.
|
|
54
|
+
*/
|
|
55
|
+
export const tonStakingDepositBuffer = 1000000000n;
|
|
56
|
+
/**
|
|
57
|
+
* Amount (nanotons) accompanying a withdraw message — the pool's 0.2 TON
|
|
58
|
+
* withdraw fee. The pool returns the full staked balance separately; sending
|
|
59
|
+
* more (e.g. 1 TON) fails.
|
|
60
|
+
*/
|
|
61
|
+
export const tonStakingWithdrawFee = 200000000n;
|
|
62
|
+
/**
|
|
63
|
+
* Conservative network-fee reserve (nanotons ≈ 0.05 TON) held back from the
|
|
64
|
+
* spendable balance when sizing a stake deposit or checking the unstake fee is
|
|
65
|
+
* affordable. Larger than the bare base fee because the text-comment cell adds
|
|
66
|
+
* compute; matches the iOS reserve.
|
|
67
|
+
*/
|
|
68
|
+
export const tonStakingFeeReserve = 50000000n;
|
|
69
|
+
const mapPoolEntry = (entry) => ({
|
|
70
|
+
// Normalize to the bounceable `EQ…` form at the boundary so no caller can
|
|
71
|
+
// build a staking transfer to a raw/non-bounceable destination (which the
|
|
72
|
+
// pool would absorb instead of bouncing back on rejection).
|
|
73
|
+
address: tonAddressToBounceable(entry.address),
|
|
74
|
+
name: entry.name,
|
|
75
|
+
apy: entry.apy,
|
|
76
|
+
minStake: BigInt(Math.trunc(entry.min_stake)),
|
|
77
|
+
verified: entry.verified,
|
|
78
|
+
currentNominators: entry.current_nominators,
|
|
79
|
+
maxNominators: entry.max_nominators,
|
|
80
|
+
implementation: entry.implementation,
|
|
81
|
+
cycleEnd: entry.cycle_end,
|
|
82
|
+
});
|
|
83
|
+
/** Whether a pool has room for another nominator (pools at capacity reject new stakes). */
|
|
84
|
+
export const tonPoolHasCapacity = (pool) => {
|
|
85
|
+
const { currentNominators, maxNominators } = pool;
|
|
86
|
+
if (currentNominators === undefined || maxNominators === undefined || maxNominators <= 0) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return currentNominators < maxNominators;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Whether a pool is a verified nominator pool with capacity — i.e. one the
|
|
93
|
+
* picker should surface and a stake can succeed into.
|
|
94
|
+
*/
|
|
95
|
+
export const isStakeableTonPool = (pool) => pool.verified && isTonNominatorImplementation(pool.implementation) && tonPoolHasCapacity(pool);
|
|
96
|
+
/**
|
|
97
|
+
* Fetches all verified TON staking pools from tonapi (`/v2/staking/pools`).
|
|
98
|
+
* Includes every implementation; callers filter to stakeable nominator pools
|
|
99
|
+
* via `isStakeableTonPool`.
|
|
100
|
+
*/
|
|
101
|
+
export const getTonStakingPools = async () => {
|
|
102
|
+
const url = `${tonApiPublicUrl}/v2/staking/pools?include_unverified=false`;
|
|
103
|
+
const { pools } = await queryUrl(url);
|
|
104
|
+
return pools.map(mapPoolEntry);
|
|
105
|
+
};
|
|
106
|
+
/** Fetches computed pool metadata (name, APY, implementation, cycle end). */
|
|
107
|
+
export const getTonStakingPoolInfo = async (poolAddress) => {
|
|
108
|
+
const url = `${tonApiPublicUrl}/v2/staking/pool/${encodeURIComponent(poolAddress)}`;
|
|
109
|
+
const { pool } = await queryUrl(url);
|
|
110
|
+
if (!pool)
|
|
111
|
+
return undefined;
|
|
112
|
+
return {
|
|
113
|
+
address: pool.address ? tonAddressToBounceable(pool.address) : undefined,
|
|
114
|
+
name: pool.name,
|
|
115
|
+
apy: pool.apy,
|
|
116
|
+
minStake: pool.min_stake !== undefined ? BigInt(Math.trunc(pool.min_stake)) : undefined,
|
|
117
|
+
implementation: pool.implementation,
|
|
118
|
+
cycleEnd: pool.cycle_end,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Fetches an account's nominator-pool positions
|
|
123
|
+
* (`/v2/staking/nominator/{accountId}/pools`) — the authoritative source for
|
|
124
|
+
* staked positions. `accountId` accepts the user-friendly wallet address.
|
|
125
|
+
*/
|
|
126
|
+
export const getTonNominatorPools = async (accountId) => {
|
|
127
|
+
const url = `${tonApiPublicUrl}/v2/staking/nominator/${encodeURIComponent(accountId)}/pools`;
|
|
128
|
+
const { pools } = await queryUrl(url);
|
|
129
|
+
return pools.map(position => ({
|
|
130
|
+
pool: tonAddressToBounceable(position.pool),
|
|
131
|
+
amount: BigInt(Math.trunc(position.amount)),
|
|
132
|
+
pendingDeposit: BigInt(Math.trunc(position.pending_deposit)),
|
|
133
|
+
pendingWithdraw: BigInt(Math.trunc(position.pending_withdraw)),
|
|
134
|
+
readyWithdraw: BigInt(Math.trunc(position.ready_withdraw)),
|
|
135
|
+
}));
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=staking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staking.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/chains/ton/staking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EvmChain } from '@vultisig/core-chain/Chain';
|
|
2
|
+
import { AccountCoinKey } from '@vultisig/core-chain/coin/AccountCoin';
|
|
3
|
+
import { Address } from 'viem';
|
|
4
|
+
export type GetEvmChainBalancesInput = {
|
|
5
|
+
chain: EvmChain;
|
|
6
|
+
address: Address;
|
|
7
|
+
coins: AccountCoinKey<EvmChain>[];
|
|
8
|
+
};
|
|
9
|
+
export type EvmChainBalances = Record<string, bigint>;
|
|
10
|
+
export declare const getEvmChainBalances: (input: GetEvmChainBalancesInput) => Promise<EvmChainBalances>;
|
|
11
|
+
//# sourceMappingURL=getEvmChainBalances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEvmChainBalances.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAErD,OAAO,EAAE,cAAc,EAA0B,MAAM,uCAAuC,CAAA;AAE9F,OAAO,EAAE,OAAO,EAAsB,MAAM,MAAM,CAAA;AAMlD,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,QAAQ,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAkBrD,eAAO,MAAM,mBAAmB,GAAU,OAAO,wBAAwB,KAAG,OAAO,CAAC,gBAAgB,CAiDnG,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getEvmClient } from '@vultisig/core-chain/chains/evm/client';
|
|
2
|
+
import { accountCoinKeyToString } from '@vultisig/core-chain/coin/AccountCoin';
|
|
3
|
+
import { isFeeCoin } from '@vultisig/core-chain/coin/utils/isFeeCoin';
|
|
4
|
+
import { erc20Abi, parseAbi } from 'viem';
|
|
5
|
+
import { getEvmCoinBalance } from './resolvers/evm.js';
|
|
6
|
+
const multicall3Abi = parseAbi(['function getEthBalance(address addr) view returns (uint256)']);
|
|
7
|
+
const getFallbackBalances = async ({ chain, address, coins }) => {
|
|
8
|
+
const entries = await Promise.all(coins.map(async (coin) => {
|
|
9
|
+
const input = { ...coin, chain, address };
|
|
10
|
+
try {
|
|
11
|
+
return [accountCoinKeyToString(input), await getEvmCoinBalance(input)];
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [accountCoinKeyToString(input), 0n];
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
return Object.fromEntries(entries);
|
|
18
|
+
};
|
|
19
|
+
export const getEvmChainBalances = async (input) => {
|
|
20
|
+
const { chain, address, coins } = input;
|
|
21
|
+
if (coins.length === 0) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const publicClient = getEvmClient(chain);
|
|
25
|
+
const multicall3Address = publicClient.chain?.contracts?.multicall3?.address;
|
|
26
|
+
if (!multicall3Address) {
|
|
27
|
+
return getFallbackBalances(input);
|
|
28
|
+
}
|
|
29
|
+
const contracts = coins.map(coin => isFeeCoin(coin)
|
|
30
|
+
? {
|
|
31
|
+
address: multicall3Address,
|
|
32
|
+
abi: multicall3Abi,
|
|
33
|
+
functionName: 'getEthBalance',
|
|
34
|
+
args: [address],
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
address: coin.id,
|
|
38
|
+
abi: erc20Abi,
|
|
39
|
+
functionName: 'balanceOf',
|
|
40
|
+
args: [address],
|
|
41
|
+
});
|
|
42
|
+
const results = await publicClient
|
|
43
|
+
.multicall({
|
|
44
|
+
allowFailure: true,
|
|
45
|
+
contracts,
|
|
46
|
+
})
|
|
47
|
+
.catch(() => undefined);
|
|
48
|
+
if (!results) {
|
|
49
|
+
return getFallbackBalances(input);
|
|
50
|
+
}
|
|
51
|
+
return Object.fromEntries(coins.map((coin, index) => {
|
|
52
|
+
const result = results[index];
|
|
53
|
+
const amount = result?.status === 'success' ? BigInt(result.result) : 0n;
|
|
54
|
+
return [accountCoinKeyToString({ ...coin, chain, address }), amount];
|
|
55
|
+
}));
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=getEvmChainBalances.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEvmChainBalances.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const generalSwapProviders: readonly ["1inch", "li.fi", "kyber", "swapkit", "cowswap"];
|
|
1
|
+
export declare const generalSwapProviders: readonly ["1inch", "li.fi", "kyber", "swapkit", "cowswap", "jupiter"];
|
|
2
2
|
export type GeneralSwapProvider = (typeof generalSwapProviders)[number];
|
|
3
3
|
export declare const generalSwapProviderName: Record<GeneralSwapProvider, string>;
|
|
4
4
|
//# sourceMappingURL=GeneralSwapProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeneralSwapProvider.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"GeneralSwapProvider.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,uEAAwE,CAAA;AAEzG,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAOvE,CAAA"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export const generalSwapProviders = ['1inch', 'li.fi', 'kyber', 'swapkit', 'cowswap'];
|
|
1
|
+
export const generalSwapProviders = ['1inch', 'li.fi', 'kyber', 'swapkit', 'cowswap', 'jupiter'];
|
|
2
2
|
export const generalSwapProviderName = {
|
|
3
3
|
'1inch': '1Inch',
|
|
4
4
|
'li.fi': 'LI.FI',
|
|
5
5
|
kyber: 'KyberSwap',
|
|
6
6
|
swapkit: 'SwapKit',
|
|
7
7
|
cowswap: 'CowSwap',
|
|
8
|
+
jupiter: 'Jupiter',
|
|
8
9
|
};
|
|
9
10
|
//# sourceMappingURL=GeneralSwapProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeneralSwapProvider.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"GeneralSwapProvider.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapProvider.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAIzG,MAAM,CAAC,MAAM,uBAAuB,GAAwC;IAC1E,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupiter is a Solana-only, same-chain aggregator. It can route SOL↔SPL and
|
|
3
|
+
* SPL↔SPL pairs that stay on Solana, and nothing else — there is no cross-chain
|
|
4
|
+
* Jupiter route. `findSwapQuote` therefore only offers Jupiter when both legs
|
|
5
|
+
* are on Solana.
|
|
6
|
+
*/
|
|
7
|
+
export declare const jupiterSwapEnabledChains: readonly [import("@vultisig/core-chain/Chain").OtherChain.Solana];
|
|
8
|
+
export type JupiterSwapEnabledChain = (typeof jupiterSwapEnabledChains)[number];
|
|
9
|
+
//# sourceMappingURL=JupiterSwapEnabledChains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JupiterSwapEnabledChains.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/jupiter/JupiterSwapEnabledChains.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,mEAA0B,CAAA;AAE/D,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Chain } from '@vultisig/core-chain/Chain';
|
|
2
|
+
/**
|
|
3
|
+
* Jupiter is a Solana-only, same-chain aggregator. It can route SOL↔SPL and
|
|
4
|
+
* SPL↔SPL pairs that stay on Solana, and nothing else — there is no cross-chain
|
|
5
|
+
* Jupiter route. `findSwapQuote` therefore only offers Jupiter when both legs
|
|
6
|
+
* are on Solana.
|
|
7
|
+
*/
|
|
8
|
+
export const jupiterSwapEnabledChains = [Chain.Solana];
|
|
9
|
+
//# sourceMappingURL=JupiterSwapEnabledChains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JupiterSwapEnabledChains.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/jupiter/JupiterSwapEnabledChains.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAU,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AccountCoin } from '@vultisig/core-chain/coin/AccountCoin';
|
|
2
|
+
import { GeneralSwapQuote } from '@vultisig/core-chain/swap/general/GeneralSwapQuote';
|
|
3
|
+
import { JupiterSwapEnabledChain } from '@vultisig/core-chain/swap/general/jupiter/JupiterSwapEnabledChains';
|
|
4
|
+
import { TransferDirection } from '@vultisig/lib-utils/TransferDirection';
|
|
5
|
+
type Input = Record<TransferDirection, AccountCoin<JupiterSwapEnabledChain>> & {
|
|
6
|
+
amount: bigint;
|
|
7
|
+
/** VULT-scaled affiliate fee in bps. `0` disables the platform fee entirely. */
|
|
8
|
+
affiliateBps?: number;
|
|
9
|
+
/** Slippage tolerance in bps (e.g. 50 = 0.5%). Defaults to 50. */
|
|
10
|
+
slippageBps?: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Fetch a Solana same-chain swap quote from Jupiter and build the signed-tx
|
|
14
|
+
* payload the keysign pipeline expects.
|
|
15
|
+
*
|
|
16
|
+
* Affiliate fee: when `affiliateBps > 0`, `platformFeeBps` is sent on the quote.
|
|
17
|
+
* The fee ATA (output mint, owner = `jupiterFeeOwnerAddress`) is derived, passed
|
|
18
|
+
* to `/swap` as `feeAccount`, and an idempotent create instruction is prepended
|
|
19
|
+
* to the returned transaction only when the quote actually returns a non-zero
|
|
20
|
+
* `platformFee.amount`. When `affiliateBps` is 0 (e.g. an Ultimate-tier VULT
|
|
21
|
+
* holder) or Jupiter floors the fee to zero, no fee account is touched.
|
|
22
|
+
*/
|
|
23
|
+
export declare const getJupiterSwapQuote: ({ from, to, amount, affiliateBps, slippageBps, }: Input) => Promise<GeneralSwapQuote>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=getJupiterSwapQuote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getJupiterSwapQuote.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/jupiter/api/getJupiterSwapQuote.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAA;AAErF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oEAAoE,CAAA;AAC5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAUzE,KAAK,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,WAAW,CAAC,uBAAuB,CAAC,CAAC,GAAG;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AA2CD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAU,kDAMvC,KAAK,KAAG,OAAO,CAAC,gBAAgB,CAuFlC,CAAA"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Chain } from '@vultisig/core-chain/Chain';
|
|
2
|
+
import { solanaConfig } from '@vultisig/core-chain/chains/solana/solanaConfig';
|
|
3
|
+
import { getJupiterConfig, jupiterFeeOwnerAddress } from '@vultisig/core-chain/swap/general/jupiter/config';
|
|
4
|
+
import { deriveJupiterFeeAccount, prependJupiterFeeAta } from './jupiterFeeAta.js';
|
|
5
|
+
/** Canonical wrapped-SOL mint, used as the mint address for native SOL legs. */
|
|
6
|
+
const solanaNativeMint = 'So11111111111111111111111111111111111111112';
|
|
7
|
+
/** Jupiter default slippage when the caller does not override (bps). */
|
|
8
|
+
const DEFAULT_JUPITER_SLIPPAGE_BPS = 50;
|
|
9
|
+
const mintFor = ({ id }) => id ?? solanaNativeMint;
|
|
10
|
+
const requestJson = async (url, init) => {
|
|
11
|
+
const response = await fetch(url, init);
|
|
12
|
+
const rawText = await response.text().catch(() => '');
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const hint = rawText ? ` ${rawText.slice(0, 200)}` : '';
|
|
15
|
+
throw new Error(`Jupiter request failed (${response.status}): ${response.statusText}${hint}`);
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(rawText);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error('Jupiter returned a non-JSON response.');
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Fetch a Solana same-chain swap quote from Jupiter and build the signed-tx
|
|
26
|
+
* payload the keysign pipeline expects.
|
|
27
|
+
*
|
|
28
|
+
* Affiliate fee: when `affiliateBps > 0`, `platformFeeBps` is sent on the quote.
|
|
29
|
+
* The fee ATA (output mint, owner = `jupiterFeeOwnerAddress`) is derived, passed
|
|
30
|
+
* to `/swap` as `feeAccount`, and an idempotent create instruction is prepended
|
|
31
|
+
* to the returned transaction only when the quote actually returns a non-zero
|
|
32
|
+
* `platformFee.amount`. When `affiliateBps` is 0 (e.g. an Ultimate-tier VULT
|
|
33
|
+
* holder) or Jupiter floors the fee to zero, no fee account is touched.
|
|
34
|
+
*/
|
|
35
|
+
export const getJupiterSwapQuote = async ({ from, to, amount, affiliateBps = 0, slippageBps = DEFAULT_JUPITER_SLIPPAGE_BPS, }) => {
|
|
36
|
+
const { baseUrl } = getJupiterConfig();
|
|
37
|
+
const inputMint = mintFor(from);
|
|
38
|
+
const outputMint = mintFor(to);
|
|
39
|
+
const requestsPlatformFee = affiliateBps > 0;
|
|
40
|
+
const quoteParams = new URLSearchParams({
|
|
41
|
+
swapMode: 'ExactIn',
|
|
42
|
+
inputMint,
|
|
43
|
+
outputMint,
|
|
44
|
+
amount: amount.toString(),
|
|
45
|
+
slippageBps: slippageBps.toString(),
|
|
46
|
+
});
|
|
47
|
+
if (requestsPlatformFee) {
|
|
48
|
+
quoteParams.set('platformFeeBps', affiliateBps.toString());
|
|
49
|
+
}
|
|
50
|
+
const quoteResponse = await requestJson(`${baseUrl}/swap/v1/quote?${quoteParams.toString()}`, {
|
|
51
|
+
headers: { Accept: 'application/json' },
|
|
52
|
+
});
|
|
53
|
+
// Gate the fee-account flow on the actually quoted fee, not just the requested
|
|
54
|
+
// bps: Jupiter can floor `platformFee.amount` to 0 (tiny amounts, route with no
|
|
55
|
+
// fee-eligible mint) even when we asked for a fee. Deriving a fee account and
|
|
56
|
+
// paying ATA rent for a zero fee would break the "no fee account when the fee
|
|
57
|
+
// floors to zero" contract. Require both a requested fee and a non-zero quoted
|
|
58
|
+
// amount before touching the fee account.
|
|
59
|
+
const swapFeeAmount = BigInt(quoteResponse.platformFee?.amount ?? '0');
|
|
60
|
+
const chargesFee = requestsPlatformFee && swapFeeAmount > 0n;
|
|
61
|
+
// The fee mint is the OUTPUT mint (ExactIn). Derive the fee ATA up front so
|
|
62
|
+
// it can be sent to /swap and so we know which program owns it for the
|
|
63
|
+
// prepended create instruction.
|
|
64
|
+
const feeAccountInfo = chargesFee
|
|
65
|
+
? await deriveJupiterFeeAccount({ outputMint, feeOwner: jupiterFeeOwnerAddress })
|
|
66
|
+
: undefined;
|
|
67
|
+
const swapResponse = await requestJson(`${baseUrl}/swap/v1/swap`, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
quoteResponse,
|
|
72
|
+
userPublicKey: from.address,
|
|
73
|
+
wrapAndUnwrapSol: true,
|
|
74
|
+
dynamicComputeUnitLimit: true,
|
|
75
|
+
...(feeAccountInfo ? { feeAccount: feeAccountInfo.feeAccount } : {}),
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
if (!swapResponse.swapTransaction) {
|
|
79
|
+
throw new Error('Jupiter swap response did not include a serialized transaction.');
|
|
80
|
+
}
|
|
81
|
+
const data = feeAccountInfo
|
|
82
|
+
? await prependJupiterFeeAta({
|
|
83
|
+
txData: swapResponse.swapTransaction,
|
|
84
|
+
feeAccount: feeAccountInfo.feeAccount,
|
|
85
|
+
mintPubkey: feeAccountInfo.mintPubkey,
|
|
86
|
+
ownerPubkey: feeAccountInfo.ownerPubkey,
|
|
87
|
+
tokenProgramId: feeAccountInfo.tokenProgramId,
|
|
88
|
+
})
|
|
89
|
+
: swapResponse.swapTransaction;
|
|
90
|
+
// Network fee is an upper-bound estimate: Solana's per-signature base fee plus
|
|
91
|
+
// the fee-ATA rent buffer when we prepend a create instruction (charged once
|
|
92
|
+
// per fee mint; idempotent thereafter). Jupiter embeds its own priority fee in
|
|
93
|
+
// the returned tx, which the consumer surfaces at broadcast time.
|
|
94
|
+
const networkFee = BigInt(solanaConfig.baseFee) + (chargesFee ? BigInt(solanaConfig.ataRentLamports) : 0n);
|
|
95
|
+
return {
|
|
96
|
+
dstAmount: quoteResponse.outAmount,
|
|
97
|
+
provider: 'jupiter',
|
|
98
|
+
tx: {
|
|
99
|
+
solana: {
|
|
100
|
+
data,
|
|
101
|
+
networkFee,
|
|
102
|
+
swapFee: {
|
|
103
|
+
amount: swapFeeAmount,
|
|
104
|
+
decimals: to.decimals,
|
|
105
|
+
chain: Chain.Solana,
|
|
106
|
+
id: to.id,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=getJupiterSwapQuote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getJupiterSwapQuote.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/jupiter/api/getJupiterSwapQuote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,iDAAiD,CAAA;AAG9E,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAA;AAI3G,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE/E,gFAAgF;AAChF,MAAM,gBAAgB,GAAG,6CAA6C,CAAA;AAEtE,wEAAwE;AACxE,MAAM,4BAA4B,GAAG,EAAE,CAAA;AAiCvC,MAAM,OAAO,GAAG,CAAC,EAAE,EAAE,EAAe,EAAU,EAAE,CAAC,EAAE,IAAI,gBAAgB,CAAA;AAEvE,MAAM,WAAW,GAAG,KAAK,EAAK,GAAW,EAAE,IAAkB,EAAc,EAAE;IAC3E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;IAErD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACvD,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,UAAU,GAAG,IAAI,EAAE,CAAC,CAAA;IAC/F,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;IAC1D,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EAAE,EACxC,IAAI,EACJ,EAAE,EACF,MAAM,EACN,YAAY,GAAG,CAAC,EAChB,WAAW,GAAG,4BAA4B,GACpC,EAA6B,EAAE;IACrC,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAA;IAEtC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,EAAE,CAAC,CAAA;IAE9B,MAAM,mBAAmB,GAAG,YAAY,GAAG,CAAC,CAAA;IAE5C,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC;QACtC,QAAQ,EAAE,SAAS;QACnB,SAAS;QACT,UAAU;QACV,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;QACzB,WAAW,EAAE,WAAW,CAAC,QAAQ,EAAE;KACpC,CAAC,CAAA;IACF,IAAI,mBAAmB,EAAE,CAAC;QACxB,WAAW,CAAC,GAAG,CAAC,gBAAgB,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,WAAW,CAAuB,GAAG,OAAO,kBAAkB,WAAW,CAAC,QAAQ,EAAE,EAAE,EAAE;QAClH,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAA;IAEF,+EAA+E;IAC/E,gFAAgF;IAChF,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,0CAA0C;IAC1C,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,IAAI,GAAG,CAAC,CAAA;IACtE,MAAM,UAAU,GAAG,mBAAmB,IAAI,aAAa,GAAG,EAAE,CAAA;IAE5D,4EAA4E;IAC5E,uEAAuE;IACvE,gCAAgC;IAChC,MAAM,cAAc,GAAG,UAAU;QAC/B,CAAC,CAAC,MAAM,uBAAuB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;QACjF,CAAC,CAAC,SAAS,CAAA;IAEb,MAAM,YAAY,GAAG,MAAM,WAAW,CAAsB,GAAG,OAAO,eAAe,EAAE;QACrF,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;QAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,aAAa;YACb,aAAa,EAAE,IAAI,CAAC,OAAO;YAC3B,gBAAgB,EAAE,IAAI;YACtB,uBAAuB,EAAE,IAAI;YAC7B,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrE,CAAC;KACH,CAAC,CAAA;IAEF,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;IACpF,CAAC;IAED,MAAM,IAAI,GAAG,cAAc;QACzB,CAAC,CAAC,MAAM,oBAAoB,CAAC;YACzB,MAAM,EAAE,YAAY,CAAC,eAAe;YACpC,UAAU,EAAE,cAAc,CAAC,UAAU;YACrC,UAAU,EAAE,cAAc,CAAC,UAAU;YACrC,WAAW,EAAE,cAAc,CAAC,WAAW;YACvC,cAAc,EAAE,cAAc,CAAC,cAAc;SAC9C,CAAC;QACJ,CAAC,CAAC,YAAY,CAAC,eAAe,CAAA;IAEhC,+EAA+E;IAC/E,6EAA6E;IAC7E,+EAA+E;IAC/E,kEAAkE;IAClE,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAE1G,OAAO;QACL,SAAS,EAAE,aAAa,CAAC,SAAS;QAClC,QAAQ,EAAE,SAAS;QACnB,EAAE,EAAE;YACF,MAAM,EAAE;gBACN,IAAI;gBACJ,UAAU;gBACV,OAAO,EAAE;oBACP,MAAM,EAAE,aAAa;oBACrB,QAAQ,EAAE,EAAE,CAAC,QAAQ;oBACrB,KAAK,EAAE,KAAK,CAAC,MAAM;oBACnB,EAAE,EAAE,EAAE,CAAC,EAAE;iBACV;aACF;SACF;KACF,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
export type JupiterFeeAccount = {
|
|
3
|
+
/** Base58 ATA address Jupiter must credit the platform fee to. */
|
|
4
|
+
feeAccount: string;
|
|
5
|
+
/** Token program (Token vs Token-2022) that owns the fee-mint. */
|
|
6
|
+
tokenProgramId: PublicKey;
|
|
7
|
+
mintPubkey: PublicKey;
|
|
8
|
+
ownerPubkey: PublicKey;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Derive the Jupiter platform-fee Associated Token Account for `(owner =
|
|
12
|
+
* feeOwner, mint = outputMint)`. Jupiter charges the affiliate fee in the
|
|
13
|
+
* OUTPUT mint (the only mint allowed for an ExactIn swap besides the input),
|
|
14
|
+
* so the fee mint is always the swap's output mint.
|
|
15
|
+
*
|
|
16
|
+
* The token program is resolved from the mint owner so Token-2022 mints derive
|
|
17
|
+
* the correct ATA. This must be called BEFORE the `/swap` request so the
|
|
18
|
+
* derived `feeAccount` can be passed to Jupiter.
|
|
19
|
+
*/
|
|
20
|
+
export declare const deriveJupiterFeeAccount: ({ outputMint, feeOwner, }: {
|
|
21
|
+
outputMint: string;
|
|
22
|
+
feeOwner: string;
|
|
23
|
+
}) => Promise<JupiterFeeAccount>;
|
|
24
|
+
/**
|
|
25
|
+
* Prepend an idempotent `createAssociatedTokenAccount` instruction for the
|
|
26
|
+
* Jupiter fee ATA to the serialized swap transaction.
|
|
27
|
+
*
|
|
28
|
+
* Jupiter's `/swap` endpoint auto-creates the *user's* output ATA but treats
|
|
29
|
+
* the `feeAccount` as a precondition it never initializes — so we must prepend
|
|
30
|
+
* our own create instruction. The idempotent variant is a no-op (no rent
|
|
31
|
+
* charged) when the ATA already exists, making this safe to run on every swap
|
|
32
|
+
* without an existence probe.
|
|
33
|
+
*
|
|
34
|
+
* Rent (~0.002 SOL, the first time per fee mint) is paid by the tx fee-payer
|
|
35
|
+
* (the user), matching the existing LiFi Solana ATA-injection behaviour.
|
|
36
|
+
*
|
|
37
|
+
* `recentBlockhash` is preserved verbatim from Jupiter's quote. The consumer's
|
|
38
|
+
* keysign path refreshes the blockhash before broadcast (same as every other
|
|
39
|
+
* Solana general-swap route), so we do not refresh it here.
|
|
40
|
+
*/
|
|
41
|
+
export declare const prependJupiterFeeAta: ({ txData, feeAccount, mintPubkey, ownerPubkey, tokenProgramId, }: {
|
|
42
|
+
txData: string;
|
|
43
|
+
feeAccount: string;
|
|
44
|
+
mintPubkey: PublicKey;
|
|
45
|
+
ownerPubkey: PublicKey;
|
|
46
|
+
tokenProgramId: PublicKey;
|
|
47
|
+
}) => Promise<string>;
|
|
48
|
+
//# sourceMappingURL=jupiterFeeAta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jupiterFeeAta.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/jupiter/api/jupiterFeeAta.ts"],"names":[],"mappings":"AAMA,OAAO,EAA6B,SAAS,EAA4C,MAAM,iBAAiB,CAAA;AAsDhH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,cAAc,EAAE,SAAS,CAAA;IACzB,UAAU,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,SAAS,CAAA;CACvB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,GAAU,2BAG3C;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB,KAAG,OAAO,CAAC,iBAAiB,CAa5B,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,GAAU,kEAMxC;IACD,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,SAAS,CAAA;IACtB,cAAc,EAAE,SAAS,CAAA;CAC1B,KAAG,OAAO,CAAC,MAAM,CAgDjB,CAAA"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID, } from '@solana/spl-token';
|
|
2
|
+
import { PublicKey, TransactionMessage, VersionedTransaction } from '@solana/web3.js';
|
|
3
|
+
import { getSolanaClient } from '@vultisig/core-chain/chains/solana/client';
|
|
4
|
+
/** Maximum attempts for LUT fetches before giving up. */
|
|
5
|
+
const MAX_LUT_FETCH_ATTEMPTS = 3;
|
|
6
|
+
/**
|
|
7
|
+
* Fetch a LUT account with simple retry (exponential back-off, up to 3 attempts).
|
|
8
|
+
* RPC timeouts are transient; retrying avoids spurious quote failures.
|
|
9
|
+
*/
|
|
10
|
+
const fetchLutWithRetry = async (client, accountKey) => {
|
|
11
|
+
const errors = [];
|
|
12
|
+
for (let attempt = 0; attempt < MAX_LUT_FETCH_ATTEMPTS; attempt++) {
|
|
13
|
+
try {
|
|
14
|
+
const result = await client.getAddressLookupTable(accountKey);
|
|
15
|
+
return result.value ?? null;
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
errors.push(err);
|
|
19
|
+
if (attempt < MAX_LUT_FETCH_ATTEMPTS - 1) {
|
|
20
|
+
await new Promise(resolve => setTimeout(resolve, 200 * 2 ** attempt));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
console.warn('[jupiterFeeAta] LUT fetch failed after retries:', errors);
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the SPL token program (Token vs Token-2022) that owns a mint.
|
|
29
|
+
*
|
|
30
|
+
* Failing to resolve the mint (RPC timeout, bad address, closed account) must
|
|
31
|
+
* throw rather than fall back to TOKEN_PROGRAM_ID — a silent fallback would
|
|
32
|
+
* derive the wrong ATA and produce an opaque simulation failure downstream.
|
|
33
|
+
*/
|
|
34
|
+
const resolveTokenProgramId = async (mintPubkey) => {
|
|
35
|
+
const client = getSolanaClient();
|
|
36
|
+
const mintInfo = await client.getAccountInfo(mintPubkey);
|
|
37
|
+
if (!mintInfo) {
|
|
38
|
+
throw new Error(`Mint account ${mintPubkey.toBase58()} not found - cannot determine Token vs Token-2022 program`);
|
|
39
|
+
}
|
|
40
|
+
if (mintInfo.owner.equals(TOKEN_PROGRAM_ID)) {
|
|
41
|
+
return TOKEN_PROGRAM_ID;
|
|
42
|
+
}
|
|
43
|
+
if (mintInfo.owner.equals(TOKEN_2022_PROGRAM_ID)) {
|
|
44
|
+
return TOKEN_2022_PROGRAM_ID;
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`Mint ${mintPubkey.toBase58()} is owned by unsupported program ${mintInfo.owner.toBase58()} - expected Token or Token-2022`);
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Derive the Jupiter platform-fee Associated Token Account for `(owner =
|
|
50
|
+
* feeOwner, mint = outputMint)`. Jupiter charges the affiliate fee in the
|
|
51
|
+
* OUTPUT mint (the only mint allowed for an ExactIn swap besides the input),
|
|
52
|
+
* so the fee mint is always the swap's output mint.
|
|
53
|
+
*
|
|
54
|
+
* The token program is resolved from the mint owner so Token-2022 mints derive
|
|
55
|
+
* the correct ATA. This must be called BEFORE the `/swap` request so the
|
|
56
|
+
* derived `feeAccount` can be passed to Jupiter.
|
|
57
|
+
*/
|
|
58
|
+
export const deriveJupiterFeeAccount = async ({ outputMint, feeOwner, }) => {
|
|
59
|
+
const mintPubkey = new PublicKey(outputMint);
|
|
60
|
+
const ownerPubkey = new PublicKey(feeOwner);
|
|
61
|
+
const tokenProgramId = await resolveTokenProgramId(mintPubkey);
|
|
62
|
+
const feeAccount = getAssociatedTokenAddressSync(mintPubkey, ownerPubkey,
|
|
63
|
+
/* allowOwnerOffCurve */ false, tokenProgramId).toBase58();
|
|
64
|
+
return { feeAccount, tokenProgramId, mintPubkey, ownerPubkey };
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Prepend an idempotent `createAssociatedTokenAccount` instruction for the
|
|
68
|
+
* Jupiter fee ATA to the serialized swap transaction.
|
|
69
|
+
*
|
|
70
|
+
* Jupiter's `/swap` endpoint auto-creates the *user's* output ATA but treats
|
|
71
|
+
* the `feeAccount` as a precondition it never initializes — so we must prepend
|
|
72
|
+
* our own create instruction. The idempotent variant is a no-op (no rent
|
|
73
|
+
* charged) when the ATA already exists, making this safe to run on every swap
|
|
74
|
+
* without an existence probe.
|
|
75
|
+
*
|
|
76
|
+
* Rent (~0.002 SOL, the first time per fee mint) is paid by the tx fee-payer
|
|
77
|
+
* (the user), matching the existing LiFi Solana ATA-injection behaviour.
|
|
78
|
+
*
|
|
79
|
+
* `recentBlockhash` is preserved verbatim from Jupiter's quote. The consumer's
|
|
80
|
+
* keysign path refreshes the blockhash before broadcast (same as every other
|
|
81
|
+
* Solana general-swap route), so we do not refresh it here.
|
|
82
|
+
*/
|
|
83
|
+
export const prependJupiterFeeAta = async ({ txData, feeAccount, mintPubkey, ownerPubkey, tokenProgramId, }) => {
|
|
84
|
+
const client = getSolanaClient();
|
|
85
|
+
const versionedTx = VersionedTransaction.deserialize(Buffer.from(txData, 'base64'));
|
|
86
|
+
const lutAccounts = [];
|
|
87
|
+
if (versionedTx.message.version === 0) {
|
|
88
|
+
const lookups = versionedTx.message.addressTableLookups;
|
|
89
|
+
for (const lut of lookups) {
|
|
90
|
+
const lutAccount = await fetchLutWithRetry(client, lut.accountKey);
|
|
91
|
+
if (lutAccount) {
|
|
92
|
+
lutAccounts.push(lutAccount);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let decompiledMessage;
|
|
97
|
+
try {
|
|
98
|
+
decompiledMessage = TransactionMessage.decompile(versionedTx.message, {
|
|
99
|
+
addressLookupTableAccounts: lutAccounts,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
throw new Error(`Failed to decompile Jupiter transaction message - one or more LUT accounts could not be resolved (fetched ${lutAccounts.length} of ${versionedTx.message.addressTableLookups?.length ?? 0} referenced LUTs). Original error: ${err instanceof Error ? err.message : String(err)}`);
|
|
104
|
+
}
|
|
105
|
+
const createFeeAtaIx = createAssociatedTokenAccountIdempotentInstruction(decompiledMessage.payerKey, new PublicKey(feeAccount), ownerPubkey, mintPubkey, tokenProgramId);
|
|
106
|
+
const updatedMessage = new TransactionMessage({
|
|
107
|
+
payerKey: decompiledMessage.payerKey,
|
|
108
|
+
recentBlockhash: decompiledMessage.recentBlockhash,
|
|
109
|
+
instructions: [createFeeAtaIx, ...decompiledMessage.instructions],
|
|
110
|
+
}).compileToV0Message(lutAccounts.length > 0 ? lutAccounts : undefined);
|
|
111
|
+
// Do NOT copy versionedTx.signatures: the message bytes changed, so any
|
|
112
|
+
// signature over the old bytes is invalid. Jupiter does not pre-sign quotes.
|
|
113
|
+
return Buffer.from(new VersionedTransaction(updatedMessage).serialize()).toString('base64');
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=jupiterFeeAta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jupiterFeeAta.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/jupiter/api/jupiterFeeAta.ts"],"names":[],"mappings":"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"}
|