@coinbarrel/sdk 1.0.1 → 1.2.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/README.md +85 -0
- package/dist/accounts.js +33 -26
- package/dist/constants.js +22 -17
- package/dist/create.js +100 -0
- package/dist/curve.js +57 -51
- package/dist/index.js +167 -21
- package/dist/metadata.js +211 -0
- package/dist/pda.js +36 -24
- package/dist/pool.js +61 -55
- package/dist/rewards.js +97 -0
- package/dist/types.js +2 -2
- package/package.json +2 -3
- package/dist/accounts.d.ts +0 -36
- package/dist/accounts.d.ts.map +0 -1
- package/dist/accounts.js.map +0 -1
- package/dist/constants.d.ts +0 -79
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/curve.d.ts +0 -37
- package/dist/curve.d.ts.map +0 -1
- package/dist/curve.js.map +0 -1
- package/dist/index.d.ts +0 -184
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/pda.d.ts +0 -51
- package/dist/pda.d.ts.map +0 -1
- package/dist/pda.js.map +0 -1
- package/dist/pool.d.ts +0 -32
- package/dist/pool.d.ts.map +0 -1
- package/dist/pool.js.map +0 -1
- package/dist/types.d.ts +0 -162
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Token Metadata Fetching
|
|
4
|
+
* Read Metaplex token metadata for CoinBarrel tokens
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getMetadataPda = getMetadataPda;
|
|
8
|
+
exports.parseMetaplexMetadata = parseMetaplexMetadata;
|
|
9
|
+
exports.getTokenMetadata = getTokenMetadata;
|
|
10
|
+
exports.getTokenMetadataJson = getTokenMetadataJson;
|
|
11
|
+
exports.batchGetTokenMetadata = batchGetTokenMetadata;
|
|
12
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
13
|
+
const constants_js_1 = require("./constants.js");
|
|
14
|
+
// ============= PDA =============
|
|
15
|
+
/**
|
|
16
|
+
* Derive Metaplex metadata PDA for a token mint
|
|
17
|
+
*/
|
|
18
|
+
function getMetadataPda(mint) {
|
|
19
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from('metadata'), constants_js_1.TOKEN_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()], constants_js_1.TOKEN_METADATA_PROGRAM_ID);
|
|
20
|
+
return pda;
|
|
21
|
+
}
|
|
22
|
+
// ============= Parsing =============
|
|
23
|
+
/**
|
|
24
|
+
* Read a length-prefixed string from buffer
|
|
25
|
+
*/
|
|
26
|
+
function readLengthPrefixedString(data, offset) {
|
|
27
|
+
const length = data.readUInt32LE(offset);
|
|
28
|
+
const start = offset + 4;
|
|
29
|
+
const end = start + length;
|
|
30
|
+
const value = data
|
|
31
|
+
.subarray(start, end)
|
|
32
|
+
.toString('utf8')
|
|
33
|
+
.replace(/\0/g, '')
|
|
34
|
+
.trim();
|
|
35
|
+
return { value, nextOffset: end };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse Metaplex metadata from raw account data
|
|
39
|
+
*
|
|
40
|
+
* Layout:
|
|
41
|
+
* - key: 1 byte
|
|
42
|
+
* - update_authority: 32 bytes
|
|
43
|
+
* - mint: 32 bytes
|
|
44
|
+
* - name: 4 bytes length + string
|
|
45
|
+
* - symbol: 4 bytes length + string
|
|
46
|
+
* - uri: 4 bytes length + string
|
|
47
|
+
*/
|
|
48
|
+
function parseMetaplexMetadata(data) {
|
|
49
|
+
try {
|
|
50
|
+
if (!data || data.length < 65)
|
|
51
|
+
return null;
|
|
52
|
+
// Skip: key (1) + update_authority (32) + mint (32) = 65 bytes
|
|
53
|
+
let offset = 1 + 32 + 32;
|
|
54
|
+
// Name
|
|
55
|
+
const name = readLengthPrefixedString(data, offset);
|
|
56
|
+
offset = name.nextOffset;
|
|
57
|
+
// Symbol
|
|
58
|
+
const symbol = readLengthPrefixedString(data, offset);
|
|
59
|
+
offset = symbol.nextOffset;
|
|
60
|
+
// URI
|
|
61
|
+
const uri = readLengthPrefixedString(data, offset);
|
|
62
|
+
return {
|
|
63
|
+
name: name.value,
|
|
64
|
+
symbol: symbol.value,
|
|
65
|
+
uri: uri.value,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// ============= Fetching =============
|
|
73
|
+
/**
|
|
74
|
+
* Fetch on-chain token metadata from Metaplex
|
|
75
|
+
*
|
|
76
|
+
* Returns the name, symbol, and URI stored on-chain.
|
|
77
|
+
* Use `getTokenMetadataJson` to also fetch the off-chain JSON.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const metadata = await getTokenMetadata(connection, tokenMint);
|
|
82
|
+
* if (metadata) {
|
|
83
|
+
* console.log(metadata.name); // "My Token"
|
|
84
|
+
* console.log(metadata.symbol); // "MTK"
|
|
85
|
+
* console.log(metadata.uri); // "https://..."
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
async function getTokenMetadata(connection, mint) {
|
|
90
|
+
try {
|
|
91
|
+
const metadataPda = getMetadataPda(mint);
|
|
92
|
+
const accountInfo = await connection.getAccountInfo(metadataPda);
|
|
93
|
+
if (!accountInfo || !accountInfo.data || accountInfo.data.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return parseMetaplexMetadata(accountInfo.data);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch on-chain Metaplex metadata and then fetch the off-chain JSON pointed to by the URI.
|
|
104
|
+
*/
|
|
105
|
+
async function getTokenMetadataJson(connection, mint, options) {
|
|
106
|
+
const meta = await getTokenMetadata(connection, mint);
|
|
107
|
+
if (!meta)
|
|
108
|
+
return null;
|
|
109
|
+
const uri = (meta.uri ?? '').replace(/\0/g, '').trim();
|
|
110
|
+
if (!uri)
|
|
111
|
+
return { ...meta };
|
|
112
|
+
try {
|
|
113
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
114
|
+
const timeoutMs = options?.timeoutMs;
|
|
115
|
+
const timeout = controller && typeof timeoutMs === 'number' && timeoutMs > 0
|
|
116
|
+
? setTimeout(() => controller.abort(), timeoutMs)
|
|
117
|
+
: null;
|
|
118
|
+
const resp = await fetch(uri, {
|
|
119
|
+
signal: controller?.signal,
|
|
120
|
+
headers: { accept: 'application/json' },
|
|
121
|
+
});
|
|
122
|
+
if (!resp.ok)
|
|
123
|
+
return { ...meta };
|
|
124
|
+
const json = (await resp.json());
|
|
125
|
+
if (timeout)
|
|
126
|
+
clearTimeout(timeout);
|
|
127
|
+
// Best-effort map of common social fields
|
|
128
|
+
const properties = json.properties && typeof json.properties === 'object'
|
|
129
|
+
? json.properties
|
|
130
|
+
: undefined;
|
|
131
|
+
const extensions = (json.extensions && typeof json.extensions === 'object'
|
|
132
|
+
? json.extensions
|
|
133
|
+
: undefined) ||
|
|
134
|
+
(properties?.extensions && typeof properties.extensions === 'object'
|
|
135
|
+
? properties.extensions
|
|
136
|
+
: undefined);
|
|
137
|
+
const twitter = (typeof json.twitter === 'string' && json.twitter) ||
|
|
138
|
+
(typeof extensions?.twitter === 'string' && extensions.twitter) ||
|
|
139
|
+
undefined;
|
|
140
|
+
const telegram = (typeof json.telegram === 'string' && json.telegram) ||
|
|
141
|
+
(typeof extensions?.telegram === 'string' && extensions.telegram) ||
|
|
142
|
+
undefined;
|
|
143
|
+
const website = (typeof json.website === 'string' && json.website) ||
|
|
144
|
+
(typeof extensions?.website === 'string' && extensions.website) ||
|
|
145
|
+
undefined;
|
|
146
|
+
return {
|
|
147
|
+
...meta,
|
|
148
|
+
...json,
|
|
149
|
+
// ensure we always surface these normalized keys when available
|
|
150
|
+
twitter,
|
|
151
|
+
telegram,
|
|
152
|
+
website,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return { ...meta };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Batch fetch metadata for multiple tokens
|
|
161
|
+
*
|
|
162
|
+
* More efficient than calling getTokenMetadata individually.
|
|
163
|
+
*
|
|
164
|
+
* @param connection - Solana RPC connection
|
|
165
|
+
* @param mints - Array of token mint addresses
|
|
166
|
+
* @returns Map of mint address string to metadata
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const mints = [mint1, mint2, mint3];
|
|
171
|
+
* const metadataMap = await batchGetTokenMetadata(connection, mints);
|
|
172
|
+
*
|
|
173
|
+
* for (const [mintStr, metadata] of metadataMap) {
|
|
174
|
+
* console.log(`${mintStr}: ${metadata?.name}`);
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
async function batchGetTokenMetadata(connection, mints) {
|
|
179
|
+
const results = new Map();
|
|
180
|
+
if (mints.length === 0) {
|
|
181
|
+
return results;
|
|
182
|
+
}
|
|
183
|
+
// Derive all metadata PDAs
|
|
184
|
+
const pdas = mints.map((mint) => ({
|
|
185
|
+
mint,
|
|
186
|
+
pda: getMetadataPda(mint),
|
|
187
|
+
}));
|
|
188
|
+
// Batch fetch all accounts
|
|
189
|
+
try {
|
|
190
|
+
const accountInfos = await connection.getMultipleAccountsInfo(pdas.map((p) => p.pda));
|
|
191
|
+
// Parse each result
|
|
192
|
+
for (let i = 0; i < pdas.length; i++) {
|
|
193
|
+
const mintStr = pdas[i].mint.toBase58();
|
|
194
|
+
const accountInfo = accountInfos[i];
|
|
195
|
+
if (accountInfo && accountInfo.data && accountInfo.data.length > 0) {
|
|
196
|
+
const metadata = parseMetaplexMetadata(accountInfo.data);
|
|
197
|
+
results.set(mintStr, metadata);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
results.set(mintStr, null);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// If batch fails, set all to null
|
|
206
|
+
for (const { mint } of pdas) {
|
|
207
|
+
results.set(mint.toBase58(), null);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return results;
|
|
211
|
+
}
|
package/dist/pda.js
CHANGED
|
@@ -1,77 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* PDA Derivation Helpers
|
|
3
4
|
* All Program Derived Addresses for CoinBarrel AMM
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getBondingCurvePda = getBondingCurvePda;
|
|
8
|
+
exports.getBondingAuthorityPda = getBondingAuthorityPda;
|
|
9
|
+
exports.getSolEscrowPda = getSolEscrowPda;
|
|
10
|
+
exports.getPoolPda = getPoolPda;
|
|
11
|
+
exports.getPoolAuthorityPda = getPoolAuthorityPda;
|
|
12
|
+
exports.getVaultPda = getVaultPda;
|
|
13
|
+
exports.getPoolWsolVaultPda = getPoolWsolVaultPda;
|
|
14
|
+
exports.getPoolTokenVaultPda = getPoolTokenVaultPda;
|
|
15
|
+
exports.getLpMintPda = getLpMintPda;
|
|
16
|
+
exports.getLpVaultPda = getLpVaultPda;
|
|
17
|
+
exports.getHolderRewardPda = getHolderRewardPda;
|
|
18
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
19
|
+
const constants_js_1 = require("./constants.js");
|
|
7
20
|
// ============= Bonding Curve PDAs =============
|
|
8
21
|
/**
|
|
9
22
|
* Derive bonding curve PDA for a token mint
|
|
10
23
|
*/
|
|
11
|
-
|
|
12
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.BONDING, mint.toBuffer()], programId);
|
|
24
|
+
function getBondingCurvePda(mint, programId) {
|
|
25
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.BONDING, mint.toBuffer()], programId);
|
|
13
26
|
return pda;
|
|
14
27
|
}
|
|
15
28
|
/**
|
|
16
29
|
* Derive bonding authority PDA (signs transfers from curve)
|
|
17
30
|
*/
|
|
18
|
-
|
|
19
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.BONDING_AUTHORITY, bondingCurve.toBuffer()], programId);
|
|
31
|
+
function getBondingAuthorityPda(bondingCurve, programId) {
|
|
32
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.BONDING_AUTHORITY, bondingCurve.toBuffer()], programId);
|
|
20
33
|
return pda;
|
|
21
34
|
}
|
|
22
35
|
/**
|
|
23
36
|
* Derive SOL escrow PDA for bonding curve
|
|
24
37
|
*/
|
|
25
|
-
|
|
26
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.BONDING_SOL, bondingCurve.toBuffer()], programId);
|
|
38
|
+
function getSolEscrowPda(bondingCurve, programId) {
|
|
39
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.BONDING_SOL, bondingCurve.toBuffer()], programId);
|
|
27
40
|
return pda;
|
|
28
41
|
}
|
|
29
42
|
// ============= AMM Pool PDAs =============
|
|
30
43
|
/**
|
|
31
44
|
* Derive pool PDA for a WSOL <-> Token pair
|
|
32
45
|
*/
|
|
33
|
-
|
|
34
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.POOL, NATIVE_MINT.toBuffer(), tokenMint.toBuffer()], programId);
|
|
46
|
+
function getPoolPda(tokenMint, programId) {
|
|
47
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.POOL, constants_js_1.NATIVE_MINT.toBuffer(), tokenMint.toBuffer()], programId);
|
|
35
48
|
return pda;
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
51
|
* Derive pool authority PDA (signs transfers from pool vaults)
|
|
39
52
|
*/
|
|
40
|
-
|
|
41
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.AUTHORITY, pool.toBuffer()], programId);
|
|
53
|
+
function getPoolAuthorityPda(pool, programId) {
|
|
54
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.AUTHORITY, pool.toBuffer()], programId);
|
|
42
55
|
return pda;
|
|
43
56
|
}
|
|
44
57
|
/**
|
|
45
58
|
* Derive vault PDA for a pool + mint
|
|
46
59
|
*/
|
|
47
|
-
|
|
48
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.VAULT, pool.toBuffer(), mint.toBuffer()], programId);
|
|
60
|
+
function getVaultPda(pool, mint, programId) {
|
|
61
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.VAULT, pool.toBuffer(), mint.toBuffer()], programId);
|
|
49
62
|
return pda;
|
|
50
63
|
}
|
|
51
64
|
/**
|
|
52
65
|
* Derive WSOL vault PDA for a pool
|
|
53
66
|
*/
|
|
54
|
-
|
|
55
|
-
return getVaultPda(pool, NATIVE_MINT, programId);
|
|
67
|
+
function getPoolWsolVaultPda(pool, programId) {
|
|
68
|
+
return getVaultPda(pool, constants_js_1.NATIVE_MINT, programId);
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
58
71
|
* Derive token vault PDA for a pool
|
|
59
72
|
*/
|
|
60
|
-
|
|
73
|
+
function getPoolTokenVaultPda(pool, tokenMint, programId) {
|
|
61
74
|
return getVaultPda(pool, tokenMint, programId);
|
|
62
75
|
}
|
|
63
76
|
/**
|
|
64
77
|
* Derive LP mint PDA for a pool
|
|
65
78
|
*/
|
|
66
|
-
|
|
67
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.LP_MINT, pool.toBuffer()], programId);
|
|
79
|
+
function getLpMintPda(pool, programId) {
|
|
80
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.LP_MINT, pool.toBuffer()], programId);
|
|
68
81
|
return pda;
|
|
69
82
|
}
|
|
70
83
|
/**
|
|
71
84
|
* Derive LP vault PDA (holds burned/locked LP tokens)
|
|
72
85
|
*/
|
|
73
|
-
|
|
74
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.LP_VAULT, pool.toBuffer()], programId);
|
|
86
|
+
function getLpVaultPda(pool, programId) {
|
|
87
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.LP_VAULT, pool.toBuffer()], programId);
|
|
75
88
|
return pda;
|
|
76
89
|
}
|
|
77
90
|
// ============= Holder Reward PDAs =============
|
|
@@ -79,8 +92,7 @@ export function getLpVaultPda(pool, programId) {
|
|
|
79
92
|
* Derive holder reward account PDA for a user + token
|
|
80
93
|
* Used for tracking holder rewards across buys/sells
|
|
81
94
|
*/
|
|
82
|
-
|
|
83
|
-
const [pda] = PublicKey.findProgramAddressSync([SEEDS.HOLDER_REWARD, tokenMint.toBuffer(), holder.toBuffer()], programId);
|
|
95
|
+
function getHolderRewardPda(tokenMint, holder, programId) {
|
|
96
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([constants_js_1.SEEDS.HOLDER_REWARD, tokenMint.toBuffer(), holder.toBuffer()], programId);
|
|
84
97
|
return pda;
|
|
85
98
|
}
|
|
86
|
-
//# sourceMappingURL=pda.js.map
|
package/dist/pool.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* AMM Pool Operations
|
|
3
4
|
* Swap tokens on graduated AMM pools
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getSwapSolToTokenQuote = getSwapSolToTokenQuote;
|
|
8
|
+
exports.getSwapTokenToSolQuote = getSwapTokenToSolQuote;
|
|
9
|
+
exports.buildSwapSolToTokenInstruction = buildSwapSolToTokenInstruction;
|
|
10
|
+
exports.buildSwapTokenToSolInstruction = buildSwapTokenToSolInstruction;
|
|
11
|
+
exports.buildSwapTokenToSolMaxInstruction = buildSwapTokenToSolMaxInstruction;
|
|
12
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
13
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
14
|
+
const constants_js_1 = require("./constants.js");
|
|
15
|
+
const pda_js_1 = require("./pda.js");
|
|
16
|
+
const accounts_js_1 = require("./accounts.js");
|
|
10
17
|
// ============= Buffer Helpers =============
|
|
11
18
|
function writeU64LE(n) {
|
|
12
19
|
const b = Buffer.alloc(8);
|
|
@@ -17,9 +24,9 @@ function writeU64LE(n) {
|
|
|
17
24
|
/**
|
|
18
25
|
* Calculate swap quote for SOL -> Token
|
|
19
26
|
*/
|
|
20
|
-
|
|
21
|
-
const balances = await getPoolBalances(connection, tokenMint, programId);
|
|
22
|
-
const state = await getPoolState(connection, tokenMint, programId);
|
|
27
|
+
async function getSwapSolToTokenQuote(connection, tokenMint, solIn, programId) {
|
|
28
|
+
const balances = await (0, accounts_js_1.getPoolBalances)(connection, tokenMint, programId);
|
|
29
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
23
30
|
if (!balances || !state)
|
|
24
31
|
return null;
|
|
25
32
|
const { solBalance, tokenBalance } = balances;
|
|
@@ -48,9 +55,9 @@ export async function getSwapSolToTokenQuote(connection, tokenMint, solIn, progr
|
|
|
48
55
|
/**
|
|
49
56
|
* Calculate swap quote for Token -> SOL
|
|
50
57
|
*/
|
|
51
|
-
|
|
52
|
-
const balances = await getPoolBalances(connection, tokenMint, programId);
|
|
53
|
-
const state = await getPoolState(connection, tokenMint, programId);
|
|
58
|
+
async function getSwapTokenToSolQuote(connection, tokenMint, tokensIn, programId) {
|
|
59
|
+
const balances = await (0, accounts_js_1.getPoolBalances)(connection, tokenMint, programId);
|
|
60
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
54
61
|
if (!balances || !state)
|
|
55
62
|
return null;
|
|
56
63
|
const { solBalance, tokenBalance } = balances;
|
|
@@ -83,31 +90,31 @@ export async function getSwapTokenToSolQuote(connection, tokenMint, tokensIn, pr
|
|
|
83
90
|
* IMPORTANT: Fee recipients are read from on-chain state and cannot be modified.
|
|
84
91
|
* The program enforces that fees go to the correct recipients.
|
|
85
92
|
*/
|
|
86
|
-
|
|
93
|
+
async function buildSwapSolToTokenInstruction(connection, params, programId) {
|
|
87
94
|
const { tokenMint, user, lamportsIn, minimumAmountOut } = params;
|
|
88
95
|
// Fetch pool state to get fee recipients and vault addresses (enforced on-chain)
|
|
89
|
-
const state = await getPoolState(connection, tokenMint, programId);
|
|
96
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
90
97
|
if (!state) {
|
|
91
98
|
throw new Error("Pool not found for this token");
|
|
92
99
|
}
|
|
93
100
|
// Determine which vault is WSOL and which is the token based on stored mints
|
|
94
|
-
const isTokenANative = state.tokenAMint.equals(NATIVE_MINT);
|
|
101
|
+
const isTokenANative = state.tokenAMint.equals(constants_js_1.NATIVE_MINT);
|
|
95
102
|
const wsolVault = isTokenANative ? state.tokenAVault : state.tokenBVault;
|
|
96
103
|
const tokenVault = isTokenANative ? state.tokenBVault : state.tokenAVault;
|
|
97
|
-
const pool = getPoolPda(tokenMint, programId);
|
|
98
|
-
const authority = getPoolAuthorityPda(pool, programId);
|
|
99
|
-
const userTokenAta = getAssociatedTokenAddressSync(tokenMint, user);
|
|
100
|
-
const holderRewardAccount = getHolderRewardPda(tokenMint, user, programId);
|
|
104
|
+
const pool = (0, pda_js_1.getPoolPda)(tokenMint, programId);
|
|
105
|
+
const authority = (0, pda_js_1.getPoolAuthorityPda)(pool, programId);
|
|
106
|
+
const userTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
|
|
107
|
+
const holderRewardAccount = (0, pda_js_1.getHolderRewardPda)(tokenMint, user, programId);
|
|
101
108
|
const instructions = [];
|
|
102
109
|
// Check if user's token ATA exists, create if needed
|
|
103
110
|
try {
|
|
104
|
-
await getAccount(connection, userTokenAta);
|
|
111
|
+
await (0, spl_token_1.getAccount)(connection, userTokenAta);
|
|
105
112
|
}
|
|
106
113
|
catch {
|
|
107
|
-
instructions.push(createAssociatedTokenAccountInstruction(user, userTokenAta, user, tokenMint));
|
|
114
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(user, userTokenAta, user, tokenMint));
|
|
108
115
|
}
|
|
109
116
|
// Build swap instruction
|
|
110
|
-
const swapIx = new TransactionInstruction({
|
|
117
|
+
const swapIx = new web3_js_1.TransactionInstruction({
|
|
111
118
|
programId,
|
|
112
119
|
keys: [
|
|
113
120
|
{ pubkey: pool, isWritable: true, isSigner: false },
|
|
@@ -121,11 +128,11 @@ export async function buildSwapSolToTokenInstruction(connection, params, program
|
|
|
121
128
|
// Holder reward account
|
|
122
129
|
{ pubkey: holderRewardAccount, isWritable: true, isSigner: false },
|
|
123
130
|
{ pubkey: user, isWritable: true, isSigner: true },
|
|
124
|
-
{ pubkey: TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
125
|
-
{ pubkey: SystemProgram.programId, isWritable: false, isSigner: false },
|
|
131
|
+
{ pubkey: spl_token_1.TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
132
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isWritable: false, isSigner: false },
|
|
126
133
|
],
|
|
127
134
|
data: Buffer.concat([
|
|
128
|
-
DISCRIMINATORS.swap_sol_to_token,
|
|
135
|
+
constants_js_1.DISCRIMINATORS.swap_sol_to_token,
|
|
129
136
|
writeU64LE(lamportsIn),
|
|
130
137
|
writeU64LE(minimumAmountOut),
|
|
131
138
|
]),
|
|
@@ -138,32 +145,32 @@ export async function buildSwapSolToTokenInstruction(connection, params, program
|
|
|
138
145
|
*
|
|
139
146
|
* IMPORTANT: Fee recipients are read from on-chain state and cannot be modified.
|
|
140
147
|
*/
|
|
141
|
-
|
|
148
|
+
async function buildSwapTokenToSolInstruction(connection, params, programId) {
|
|
142
149
|
const { tokenMint, user, amountIn, minimumLamportsOut } = params;
|
|
143
150
|
// Fetch pool state to get fee recipients and vault addresses (enforced on-chain)
|
|
144
|
-
const state = await getPoolState(connection, tokenMint, programId);
|
|
151
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
145
152
|
if (!state) {
|
|
146
153
|
throw new Error("Pool not found for this token");
|
|
147
154
|
}
|
|
148
155
|
// Determine which vault is WSOL and which is the token based on stored mints
|
|
149
|
-
const isTokenANative = state.tokenAMint.equals(NATIVE_MINT);
|
|
156
|
+
const isTokenANative = state.tokenAMint.equals(constants_js_1.NATIVE_MINT);
|
|
150
157
|
const wsolVault = isTokenANative ? state.tokenAVault : state.tokenBVault;
|
|
151
158
|
const tokenVault = isTokenANative ? state.tokenBVault : state.tokenAVault;
|
|
152
|
-
const pool = getPoolPda(tokenMint, programId);
|
|
153
|
-
const authority = getPoolAuthorityPda(pool, programId);
|
|
154
|
-
const userTokenAta = getAssociatedTokenAddressSync(tokenMint, user);
|
|
155
|
-
const userWsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, user);
|
|
156
|
-
const holderRewardAccount = getHolderRewardPda(tokenMint, user, programId);
|
|
159
|
+
const pool = (0, pda_js_1.getPoolPda)(tokenMint, programId);
|
|
160
|
+
const authority = (0, pda_js_1.getPoolAuthorityPda)(pool, programId);
|
|
161
|
+
const userTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
|
|
162
|
+
const userWsolAta = (0, spl_token_1.getAssociatedTokenAddressSync)(constants_js_1.NATIVE_MINT, user);
|
|
163
|
+
const holderRewardAccount = (0, pda_js_1.getHolderRewardPda)(tokenMint, user, programId);
|
|
157
164
|
const instructions = [];
|
|
158
165
|
// Create WSOL ATA if needed (for receiving output)
|
|
159
166
|
try {
|
|
160
|
-
await getAccount(connection, userWsolAta);
|
|
167
|
+
await (0, spl_token_1.getAccount)(connection, userWsolAta);
|
|
161
168
|
}
|
|
162
169
|
catch {
|
|
163
|
-
instructions.push(createAssociatedTokenAccountInstruction(user, userWsolAta, user, NATIVE_MINT));
|
|
170
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(user, userWsolAta, user, constants_js_1.NATIVE_MINT));
|
|
164
171
|
}
|
|
165
172
|
// Build swap instruction
|
|
166
|
-
const swapIx = new TransactionInstruction({
|
|
173
|
+
const swapIx = new web3_js_1.TransactionInstruction({
|
|
167
174
|
programId,
|
|
168
175
|
keys: [
|
|
169
176
|
{ pubkey: pool, isWritable: true, isSigner: false },
|
|
@@ -178,49 +185,49 @@ export async function buildSwapTokenToSolInstruction(connection, params, program
|
|
|
178
185
|
// Holder reward account
|
|
179
186
|
{ pubkey: holderRewardAccount, isWritable: true, isSigner: false },
|
|
180
187
|
{ pubkey: user, isWritable: true, isSigner: true },
|
|
181
|
-
{ pubkey: TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
182
|
-
{ pubkey: SystemProgram.programId, isWritable: false, isSigner: false },
|
|
188
|
+
{ pubkey: spl_token_1.TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
189
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isWritable: false, isSigner: false },
|
|
183
190
|
],
|
|
184
191
|
data: Buffer.concat([
|
|
185
|
-
DISCRIMINATORS.swap_token_to_sol,
|
|
192
|
+
constants_js_1.DISCRIMINATORS.swap_token_to_sol,
|
|
186
193
|
writeU64LE(amountIn),
|
|
187
194
|
writeU64LE(minimumLamportsOut),
|
|
188
195
|
]),
|
|
189
196
|
});
|
|
190
197
|
instructions.push(swapIx);
|
|
191
198
|
// Close WSOL account to unwrap to SOL
|
|
192
|
-
instructions.push(createCloseAccountInstruction(userWsolAta, user, user));
|
|
199
|
+
instructions.push((0, spl_token_1.createCloseAccountInstruction)(userWsolAta, user, user));
|
|
193
200
|
return instructions;
|
|
194
201
|
}
|
|
195
202
|
/**
|
|
196
203
|
* Build swap_token_to_sol_max instruction (sell entire balance)
|
|
197
204
|
*/
|
|
198
|
-
|
|
205
|
+
async function buildSwapTokenToSolMaxInstruction(connection, params, programId) {
|
|
199
206
|
const { tokenMint, user } = params;
|
|
200
207
|
// Fetch pool state to get fee recipients and vault addresses (enforced on-chain)
|
|
201
|
-
const state = await getPoolState(connection, tokenMint, programId);
|
|
208
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
202
209
|
if (!state) {
|
|
203
210
|
throw new Error("Pool not found for this token");
|
|
204
211
|
}
|
|
205
212
|
// Determine which vault is WSOL and which is the token based on stored mints
|
|
206
|
-
const isTokenANative = state.tokenAMint.equals(NATIVE_MINT);
|
|
213
|
+
const isTokenANative = state.tokenAMint.equals(constants_js_1.NATIVE_MINT);
|
|
207
214
|
const wsolVault = isTokenANative ? state.tokenAVault : state.tokenBVault;
|
|
208
215
|
const tokenVault = isTokenANative ? state.tokenBVault : state.tokenAVault;
|
|
209
|
-
const pool = getPoolPda(tokenMint, programId);
|
|
210
|
-
const authority = getPoolAuthorityPda(pool, programId);
|
|
211
|
-
const userTokenAta = getAssociatedTokenAddressSync(tokenMint, user);
|
|
212
|
-
const userWsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, user);
|
|
213
|
-
const holderRewardAccount = getHolderRewardPda(tokenMint, user, programId);
|
|
216
|
+
const pool = (0, pda_js_1.getPoolPda)(tokenMint, programId);
|
|
217
|
+
const authority = (0, pda_js_1.getPoolAuthorityPda)(pool, programId);
|
|
218
|
+
const userTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
|
|
219
|
+
const userWsolAta = (0, spl_token_1.getAssociatedTokenAddressSync)(constants_js_1.NATIVE_MINT, user);
|
|
220
|
+
const holderRewardAccount = (0, pda_js_1.getHolderRewardPda)(tokenMint, user, programId);
|
|
214
221
|
const instructions = [];
|
|
215
222
|
// Create WSOL ATA if needed (for receiving output)
|
|
216
223
|
try {
|
|
217
|
-
await getAccount(connection, userWsolAta);
|
|
224
|
+
await (0, spl_token_1.getAccount)(connection, userWsolAta);
|
|
218
225
|
}
|
|
219
226
|
catch {
|
|
220
|
-
instructions.push(createAssociatedTokenAccountInstruction(user, userWsolAta, user, NATIVE_MINT));
|
|
227
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(user, userWsolAta, user, constants_js_1.NATIVE_MINT));
|
|
221
228
|
}
|
|
222
229
|
// Build swap max instruction
|
|
223
|
-
const swapMaxIx = new TransactionInstruction({
|
|
230
|
+
const swapMaxIx = new web3_js_1.TransactionInstruction({
|
|
224
231
|
programId,
|
|
225
232
|
keys: [
|
|
226
233
|
{ pubkey: pool, isWritable: true, isSigner: false },
|
|
@@ -235,14 +242,13 @@ export async function buildSwapTokenToSolMaxInstruction(connection, params, prog
|
|
|
235
242
|
// Holder reward account
|
|
236
243
|
{ pubkey: holderRewardAccount, isWritable: true, isSigner: false },
|
|
237
244
|
{ pubkey: user, isWritable: true, isSigner: true },
|
|
238
|
-
{ pubkey: TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
239
|
-
{ pubkey: SystemProgram.programId, isWritable: false, isSigner: false },
|
|
245
|
+
{ pubkey: spl_token_1.TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
246
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isWritable: false, isSigner: false },
|
|
240
247
|
],
|
|
241
|
-
data: DISCRIMINATORS.swap_token_to_sol_max,
|
|
248
|
+
data: constants_js_1.DISCRIMINATORS.swap_token_to_sol_max,
|
|
242
249
|
});
|
|
243
250
|
instructions.push(swapMaxIx);
|
|
244
251
|
// Close WSOL account to unwrap to SOL
|
|
245
|
-
instructions.push(createCloseAccountInstruction(userWsolAta, user, user));
|
|
252
|
+
instructions.push((0, spl_token_1.createCloseAccountInstruction)(userWsolAta, user, user));
|
|
246
253
|
return instructions;
|
|
247
254
|
}
|
|
248
|
-
//# sourceMappingURL=pool.js.map
|
package/dist/rewards.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Holder Rewards
|
|
4
|
+
* Claim accumulated holder rewards from bonding curves and AMM pools
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.buildClaimHolderRewardsCurveInstruction = buildClaimHolderRewardsCurveInstruction;
|
|
8
|
+
exports.buildClaimHolderRewardsInstruction = buildClaimHolderRewardsInstruction;
|
|
9
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
10
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
11
|
+
const constants_js_1 = require("./constants.js");
|
|
12
|
+
const pda_js_1 = require("./pda.js");
|
|
13
|
+
const accounts_js_1 = require("./accounts.js");
|
|
14
|
+
// ============= Claim from Bonding Curve =============
|
|
15
|
+
/**
|
|
16
|
+
* Build claim_holder_rewards_curve instruction
|
|
17
|
+
*
|
|
18
|
+
* Claims accumulated holder rewards from a bonding curve.
|
|
19
|
+
* Rewards are paid in SOL directly to the holder's wallet.
|
|
20
|
+
*/
|
|
21
|
+
async function buildClaimHolderRewardsCurveInstruction(connection, params, programId) {
|
|
22
|
+
const { tokenMint, holder } = params;
|
|
23
|
+
// Derive PDAs
|
|
24
|
+
const bondingCurve = (0, pda_js_1.getBondingCurvePda)(tokenMint, programId);
|
|
25
|
+
const solEscrow = (0, pda_js_1.getSolEscrowPda)(bondingCurve, programId);
|
|
26
|
+
const holderTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, holder);
|
|
27
|
+
const holderRewardAccount = (0, pda_js_1.getHolderRewardPda)(tokenMint, holder, programId);
|
|
28
|
+
const claimIx = new web3_js_1.TransactionInstruction({
|
|
29
|
+
programId,
|
|
30
|
+
keys: [
|
|
31
|
+
{ pubkey: bondingCurve, isWritable: true, isSigner: false },
|
|
32
|
+
{ pubkey: tokenMint, isWritable: false, isSigner: false },
|
|
33
|
+
{ pubkey: solEscrow, isWritable: true, isSigner: false },
|
|
34
|
+
{ pubkey: holderTokenAccount, isWritable: false, isSigner: false },
|
|
35
|
+
{ pubkey: holderRewardAccount, isWritable: true, isSigner: false },
|
|
36
|
+
{ pubkey: holder, isWritable: true, isSigner: true },
|
|
37
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isWritable: false, isSigner: false },
|
|
38
|
+
],
|
|
39
|
+
data: constants_js_1.DISCRIMINATORS.claim_holder_rewards_curve,
|
|
40
|
+
});
|
|
41
|
+
return [claimIx];
|
|
42
|
+
}
|
|
43
|
+
// ============= Claim from AMM Pool =============
|
|
44
|
+
/**
|
|
45
|
+
* Build claim_holder_rewards instruction
|
|
46
|
+
*
|
|
47
|
+
* Claims accumulated holder rewards from an AMM pool (post-graduation).
|
|
48
|
+
* Rewards are paid in WSOL which is then unwrapped to SOL.
|
|
49
|
+
*/
|
|
50
|
+
async function buildClaimHolderRewardsInstruction(connection, params, programId) {
|
|
51
|
+
const { tokenMint, holder } = params;
|
|
52
|
+
// Fetch pool state
|
|
53
|
+
const state = await (0, accounts_js_1.getPoolState)(connection, tokenMint, programId);
|
|
54
|
+
if (!state) {
|
|
55
|
+
throw new Error('Pool not found for this token');
|
|
56
|
+
}
|
|
57
|
+
// Derive PDAs
|
|
58
|
+
const pool = (0, pda_js_1.getPoolPda)(tokenMint, programId);
|
|
59
|
+
const authority = (0, pda_js_1.getPoolAuthorityPda)(pool, programId);
|
|
60
|
+
const holderTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, holder);
|
|
61
|
+
const holderRewardAccount = (0, pda_js_1.getHolderRewardPda)(tokenMint, holder, programId);
|
|
62
|
+
const holderWsolAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(constants_js_1.NATIVE_MINT, holder);
|
|
63
|
+
// Determine which vault is which
|
|
64
|
+
const isTokenANative = state.tokenAMint.equals(constants_js_1.NATIVE_MINT);
|
|
65
|
+
const solVault = isTokenANative ? state.tokenAVault : state.tokenBVault;
|
|
66
|
+
const tokenVault = isTokenANative ? state.tokenBVault : state.tokenAVault;
|
|
67
|
+
const instructions = [];
|
|
68
|
+
// Create WSOL ATA if needed
|
|
69
|
+
try {
|
|
70
|
+
await (0, spl_token_1.getAccount)(connection, holderWsolAccount);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(holder, holderWsolAccount, holder, constants_js_1.NATIVE_MINT));
|
|
74
|
+
}
|
|
75
|
+
const claimIx = new web3_js_1.TransactionInstruction({
|
|
76
|
+
programId,
|
|
77
|
+
keys: [
|
|
78
|
+
{ pubkey: pool, isWritable: true, isSigner: false },
|
|
79
|
+
{ pubkey: tokenMint, isWritable: false, isSigner: false },
|
|
80
|
+
{ pubkey: state.lpMint, isWritable: false, isSigner: false },
|
|
81
|
+
{ pubkey: tokenVault, isWritable: false, isSigner: false },
|
|
82
|
+
{ pubkey: solVault, isWritable: true, isSigner: false },
|
|
83
|
+
{ pubkey: holderTokenAccount, isWritable: false, isSigner: false },
|
|
84
|
+
{ pubkey: holderWsolAccount, isWritable: true, isSigner: false },
|
|
85
|
+
{ pubkey: holderRewardAccount, isWritable: true, isSigner: false },
|
|
86
|
+
{ pubkey: authority, isWritable: false, isSigner: false },
|
|
87
|
+
{ pubkey: holder, isWritable: true, isSigner: true },
|
|
88
|
+
{ pubkey: spl_token_1.TOKEN_PROGRAM_ID, isWritable: false, isSigner: false },
|
|
89
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isWritable: false, isSigner: false },
|
|
90
|
+
],
|
|
91
|
+
data: constants_js_1.DISCRIMINATORS.claim_holder_rewards,
|
|
92
|
+
});
|
|
93
|
+
instructions.push(claimIx);
|
|
94
|
+
// Close WSOL account to unwrap to SOL
|
|
95
|
+
instructions.push((0, spl_token_1.createCloseAccountInstruction)(holderWsolAccount, holder, holder));
|
|
96
|
+
return instructions;
|
|
97
|
+
}
|