@exodus/solana-lib 1.2.7 → 1.2.8
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/package.json +2 -2
- package/src/transaction.js +55 -2
- package/src/tx/create-unsigned-tx.js +10 -0
- package/src/tx/parse-unsigned-tx.js +9 -0
- package/src/tx/sign-unsigned-tx.js +53 -13
- package/src/vendor/stake-program.js +0 -148
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "Exodus internal Solana low-level library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"create-hash": "~1.1.3",
|
|
23
23
|
"tweetnacl": "^1.0.3"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "0dc8adf4a7d4d6dc3d0785f5b5d39e0a6bfb23cd"
|
|
26
26
|
}
|
package/src/transaction.js
CHANGED
|
@@ -130,15 +130,17 @@ class Tx {
|
|
|
130
130
|
assert(amountLeft === 0, `Not enough balance to send ${amount} ${token.tokenSymbol}`)
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
static createStakeAccountTransaction({ address, amount, seed = SEED, recentBlockhash }) {
|
|
133
|
+
static createStakeAccountTransaction({ address, amount, seed = SEED, pool, recentBlockhash }) {
|
|
134
134
|
const fromPubkey = new PublicKey(address)
|
|
135
135
|
const stakeAddress = createStakeAddress(address, seed)
|
|
136
136
|
const stakePublicKey = new PublicKey(stakeAddress)
|
|
137
|
+
const poolKey = new PublicKey(pool)
|
|
137
138
|
|
|
138
139
|
const authorized = new Authorized(fromPubkey, fromPubkey) // staker, withdrawer
|
|
139
140
|
const lockup = new Lockup(0, 0, fromPubkey) // no lockup
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
// create account instruction
|
|
143
|
+
const programTx = StakeProgram.createAccountWithSeed({
|
|
142
144
|
fromPubkey,
|
|
143
145
|
stakePubkey: stakePublicKey,
|
|
144
146
|
basePubkey: fromPubkey,
|
|
@@ -147,6 +149,48 @@ class Tx {
|
|
|
147
149
|
lockup,
|
|
148
150
|
lamports: amount, // number
|
|
149
151
|
})
|
|
152
|
+
|
|
153
|
+
// delegate funds instruction
|
|
154
|
+
const delegateTx = StakeProgram.delegate({
|
|
155
|
+
stakePubkey: stakePublicKey,
|
|
156
|
+
authorizedPubkey: fromPubkey,
|
|
157
|
+
votePubkey: poolKey, // pool vote key
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
const transaction = new Transaction({ recentBlockhash }).add(programTx).add(delegateTx)
|
|
161
|
+
return transaction
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static undelegate({ address, stakeAddresses, recentBlockhash }) {
|
|
165
|
+
// undelegate all stake addresses
|
|
166
|
+
assert(Array.isArray(stakeAddresses), 'stakeAddresses Array is required')
|
|
167
|
+
|
|
168
|
+
const fromPubkey = new PublicKey(address)
|
|
169
|
+
const transaction = new Transaction({ recentBlockhash })
|
|
170
|
+
|
|
171
|
+
stakeAddresses.forEach((stakeAddress) => {
|
|
172
|
+
const stakePublicKey = new PublicKey(stakeAddress)
|
|
173
|
+
const programTx = StakeProgram.deactivate({
|
|
174
|
+
stakePubkey: stakePublicKey,
|
|
175
|
+
authorizedPubkey: fromPubkey,
|
|
176
|
+
})
|
|
177
|
+
transaction.add(programTx)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return transaction
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static withdraw({ address, stakeAddresses, amount, recentBlockhash }) {
|
|
184
|
+
const fromPubkey = new PublicKey(address)
|
|
185
|
+
const stakeAddress = Array.isArray(stakeAddresses) ? stakeAddresses[0] : stakeAddresses
|
|
186
|
+
const stakePublicKey = new PublicKey(stakeAddress)
|
|
187
|
+
|
|
188
|
+
const transaction = StakeProgram.withdraw({
|
|
189
|
+
stakePubkey: stakePublicKey,
|
|
190
|
+
authorizedPubkey: fromPubkey,
|
|
191
|
+
toPubkey: fromPubkey,
|
|
192
|
+
lamports: amount,
|
|
193
|
+
})
|
|
150
194
|
transaction.recentBlockhash = recentBlockhash
|
|
151
195
|
return transaction
|
|
152
196
|
}
|
|
@@ -182,6 +226,15 @@ class Tx {
|
|
|
182
226
|
}
|
|
183
227
|
return bs58.encode(this.transaction.signature)
|
|
184
228
|
}
|
|
229
|
+
|
|
230
|
+
static getTxId(tx) {
|
|
231
|
+
let transaction = tx
|
|
232
|
+
if (tx instanceof Tx) transaction = tx.transaction
|
|
233
|
+
if (!transaction.signature) {
|
|
234
|
+
throw new Error('Cannot get txId, tx is not signed')
|
|
235
|
+
}
|
|
236
|
+
return bs58.encode(transaction.signature)
|
|
237
|
+
}
|
|
185
238
|
}
|
|
186
239
|
|
|
187
240
|
export default Tx
|
|
@@ -11,6 +11,11 @@ export function createUnsignedTx({
|
|
|
11
11
|
destinationAddressType,
|
|
12
12
|
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
13
13
|
fromTokenAddresses, // sender token addresses
|
|
14
|
+
// Staking related:
|
|
15
|
+
method,
|
|
16
|
+
stakeAddresses,
|
|
17
|
+
seed,
|
|
18
|
+
pool,
|
|
14
19
|
}: ParsedTransaction): UnsignedTransaction {
|
|
15
20
|
return {
|
|
16
21
|
txData: {
|
|
@@ -23,6 +28,11 @@ export function createUnsignedTx({
|
|
|
23
28
|
destinationAddressType,
|
|
24
29
|
isAssociatedTokenAccountActive,
|
|
25
30
|
fromTokenAddresses,
|
|
31
|
+
// Staking related:
|
|
32
|
+
method,
|
|
33
|
+
stakeAddresses,
|
|
34
|
+
seed,
|
|
35
|
+
pool,
|
|
26
36
|
},
|
|
27
37
|
txMeta: {
|
|
28
38
|
assetName: asset.name,
|
|
@@ -11,6 +11,10 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
11
11
|
destinationAddressType,
|
|
12
12
|
isAssociatedTokenAccountActive,
|
|
13
13
|
fromTokenAddresses,
|
|
14
|
+
method,
|
|
15
|
+
stakeAddresses,
|
|
16
|
+
seed,
|
|
17
|
+
pool,
|
|
14
18
|
...txData
|
|
15
19
|
} = unsignedTx.txData
|
|
16
20
|
|
|
@@ -26,5 +30,10 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
26
30
|
destinationAddressType,
|
|
27
31
|
isAssociatedTokenAccountActive,
|
|
28
32
|
fromTokenAddresses,
|
|
33
|
+
// staking related
|
|
34
|
+
method,
|
|
35
|
+
stakeAddresses,
|
|
36
|
+
seed,
|
|
37
|
+
pool,
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -9,30 +9,70 @@ export function signUnsignedTx(
|
|
|
9
9
|
const {
|
|
10
10
|
from,
|
|
11
11
|
to,
|
|
12
|
-
amount,
|
|
12
|
+
amount: unitAmount,
|
|
13
13
|
recentBlockhash,
|
|
14
|
+
// tokens related
|
|
14
15
|
tokenName,
|
|
15
16
|
destinationAddressType,
|
|
16
17
|
isAssociatedTokenAccountActive,
|
|
17
18
|
fromTokenAddresses,
|
|
19
|
+
// staking related
|
|
20
|
+
stakeAddresses,
|
|
21
|
+
method,
|
|
22
|
+
seed,
|
|
23
|
+
pool,
|
|
18
24
|
} = unsignedTx.txData
|
|
19
25
|
|
|
20
26
|
const asset = assets.solana
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
|
|
28
|
+
const address = from
|
|
29
|
+
const amount = unitAmount ? asset.currency.baseUnit(unitAmount).toNumber() : unitAmount
|
|
30
|
+
|
|
31
|
+
let tx
|
|
32
|
+
switch (method) {
|
|
33
|
+
case 'delegate':
|
|
34
|
+
tx = Transaction.createStakeAccountTransaction({
|
|
35
|
+
address,
|
|
36
|
+
amount,
|
|
37
|
+
recentBlockhash,
|
|
38
|
+
seed,
|
|
39
|
+
pool,
|
|
40
|
+
})
|
|
41
|
+
break
|
|
42
|
+
case 'undelegate':
|
|
43
|
+
tx = Transaction.undelegate({
|
|
44
|
+
address,
|
|
45
|
+
stakeAddresses,
|
|
46
|
+
recentBlockhash,
|
|
47
|
+
})
|
|
48
|
+
break
|
|
49
|
+
case 'withdraw':
|
|
50
|
+
tx = Transaction.withdraw({
|
|
51
|
+
address,
|
|
52
|
+
stakeAddresses,
|
|
53
|
+
amount,
|
|
54
|
+
recentBlockhash,
|
|
55
|
+
})
|
|
56
|
+
break
|
|
57
|
+
default:
|
|
58
|
+
// SOL and Token tx
|
|
59
|
+
tx = new Transaction({
|
|
60
|
+
from,
|
|
61
|
+
to,
|
|
62
|
+
amount,
|
|
63
|
+
recentBlockhash,
|
|
64
|
+
tokenName,
|
|
65
|
+
destinationAddressType,
|
|
66
|
+
isAssociatedTokenAccountActive,
|
|
67
|
+
fromTokenAddresses,
|
|
68
|
+
})
|
|
69
|
+
break
|
|
70
|
+
}
|
|
31
71
|
|
|
32
72
|
// sign plain tx
|
|
33
73
|
Transaction.sign(tx, privateKey)
|
|
34
|
-
const rawTx =
|
|
35
|
-
const txId =
|
|
74
|
+
const rawTx = Transaction.serialize(tx)
|
|
75
|
+
const txId = Transaction.getTxId(tx)
|
|
36
76
|
|
|
37
77
|
return { txId, rawTx }
|
|
38
78
|
}
|
|
@@ -298,68 +298,6 @@ export class StakeInstruction {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
/**
|
|
302
|
-
* Decode an authorize stake instruction and retrieve the instruction params.
|
|
303
|
-
*/
|
|
304
|
-
static decodeAuthorize(instruction: TransactionInstruction): AuthorizeStakeParams {
|
|
305
|
-
this.checkProgramId(instruction.programId)
|
|
306
|
-
this.checkKeyLength(instruction.keys, 3)
|
|
307
|
-
const { newAuthorized, stakeAuthorizationType } = decodeData(
|
|
308
|
-
STAKE_INSTRUCTION_LAYOUTS.Authorize,
|
|
309
|
-
instruction.data
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
return {
|
|
313
|
-
stakePubkey: instruction.keys[0].pubkey,
|
|
314
|
-
authorizedPubkey: instruction.keys[2].pubkey,
|
|
315
|
-
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
|
316
|
-
stakeAuthorizationType: {
|
|
317
|
-
index: stakeAuthorizationType,
|
|
318
|
-
},
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Decode an authorize-with-seed stake instruction and retrieve the instruction params.
|
|
324
|
-
*/
|
|
325
|
-
static decodeAuthorizeWithSeed(
|
|
326
|
-
instruction: TransactionInstruction
|
|
327
|
-
): AuthorizeWithSeedStakeParams {
|
|
328
|
-
this.checkProgramId(instruction.programId)
|
|
329
|
-
this.checkKeyLength(instruction.keys, 2)
|
|
330
|
-
const { newAuthorized, stakeAuthorizationType, authoritySeed, authorityOwner } = decodeData(
|
|
331
|
-
STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed,
|
|
332
|
-
instruction.data
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
return {
|
|
336
|
-
stakePubkey: instruction.keys[0].pubkey,
|
|
337
|
-
authorityBase: instruction.keys[1].pubkey,
|
|
338
|
-
authoritySeed: authoritySeed,
|
|
339
|
-
authorityOwner: new PublicKey(authorityOwner),
|
|
340
|
-
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
|
341
|
-
stakeAuthorizationType: {
|
|
342
|
-
index: stakeAuthorizationType,
|
|
343
|
-
},
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Decode a split stake instruction and retrieve the instruction params.
|
|
349
|
-
*/
|
|
350
|
-
static decodeSplit(instruction: TransactionInstruction): SplitStakeParams {
|
|
351
|
-
this.checkProgramId(instruction.programId)
|
|
352
|
-
this.checkKeyLength(instruction.keys, 3)
|
|
353
|
-
const { lamports } = decodeData(STAKE_INSTRUCTION_LAYOUTS.Split, instruction.data)
|
|
354
|
-
|
|
355
|
-
return {
|
|
356
|
-
stakePubkey: instruction.keys[0].pubkey,
|
|
357
|
-
splitStakePubkey: instruction.keys[1].pubkey,
|
|
358
|
-
authorizedPubkey: instruction.keys[2].pubkey,
|
|
359
|
-
lamports,
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
301
|
/**
|
|
364
302
|
* Decode a withdraw stake instruction and retrieve the instruction params.
|
|
365
303
|
*/
|
|
@@ -543,92 +481,6 @@ export class StakeProgram {
|
|
|
543
481
|
})
|
|
544
482
|
}
|
|
545
483
|
|
|
546
|
-
/**
|
|
547
|
-
* Generate a Transaction that authorizes a new PublicKey as Staker
|
|
548
|
-
* or Withdrawer on the Stake account.
|
|
549
|
-
*/
|
|
550
|
-
static authorize(params: AuthorizeStakeParams): Transaction {
|
|
551
|
-
const { stakePubkey, authorizedPubkey, newAuthorizedPubkey, stakeAuthorizationType } = params
|
|
552
|
-
|
|
553
|
-
const type = STAKE_INSTRUCTION_LAYOUTS.Authorize
|
|
554
|
-
const data = encodeData(type, {
|
|
555
|
-
newAuthorized: newAuthorizedPubkey.toBuffer(),
|
|
556
|
-
stakeAuthorizationType: stakeAuthorizationType.index,
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
return new Transaction().add({
|
|
560
|
-
keys: [
|
|
561
|
-
{ pubkey: stakePubkey, isSigner: false, isWritable: true },
|
|
562
|
-
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: true },
|
|
563
|
-
{ pubkey: authorizedPubkey, isSigner: true, isWritable: false },
|
|
564
|
-
],
|
|
565
|
-
programId: this.programId,
|
|
566
|
-
data,
|
|
567
|
-
})
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Generate a Transaction that authorizes a new PublicKey as Staker
|
|
572
|
-
* or Withdrawer on the Stake account.
|
|
573
|
-
*/
|
|
574
|
-
static authorizeWithSeed(params: AuthorizeWithSeedStakeParams): Transaction {
|
|
575
|
-
const {
|
|
576
|
-
stakePubkey,
|
|
577
|
-
authorityBase,
|
|
578
|
-
authoritySeed,
|
|
579
|
-
authorityOwner,
|
|
580
|
-
newAuthorizedPubkey,
|
|
581
|
-
stakeAuthorizationType,
|
|
582
|
-
} = params
|
|
583
|
-
|
|
584
|
-
const type = STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed
|
|
585
|
-
const data = encodeData(type, {
|
|
586
|
-
newAuthorized: newAuthorizedPubkey.toBuffer(),
|
|
587
|
-
stakeAuthorizationType: stakeAuthorizationType.index,
|
|
588
|
-
authoritySeed: authoritySeed,
|
|
589
|
-
authorityOwner: authorityOwner.toBuffer(),
|
|
590
|
-
})
|
|
591
|
-
|
|
592
|
-
return new Transaction().add({
|
|
593
|
-
keys: [
|
|
594
|
-
{ pubkey: stakePubkey, isSigner: false, isWritable: true },
|
|
595
|
-
{ pubkey: authorityBase, isSigner: true, isWritable: false },
|
|
596
|
-
],
|
|
597
|
-
programId: this.programId,
|
|
598
|
-
data,
|
|
599
|
-
})
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Generate a Transaction that splits Stake tokens into another stake account
|
|
604
|
-
*/
|
|
605
|
-
static split(params: SplitStakeParams): Transaction {
|
|
606
|
-
const { stakePubkey, authorizedPubkey, splitStakePubkey, lamports } = params
|
|
607
|
-
|
|
608
|
-
const transaction = new Transaction()
|
|
609
|
-
transaction.add(
|
|
610
|
-
SystemProgram.createAccount({
|
|
611
|
-
fromPubkey: authorizedPubkey,
|
|
612
|
-
newAccountPubkey: splitStakePubkey,
|
|
613
|
-
lamports: 0,
|
|
614
|
-
space: this.space,
|
|
615
|
-
programId: this.programId,
|
|
616
|
-
})
|
|
617
|
-
)
|
|
618
|
-
const type = STAKE_INSTRUCTION_LAYOUTS.Split
|
|
619
|
-
const data = encodeData(type, { lamports })
|
|
620
|
-
|
|
621
|
-
return transaction.add({
|
|
622
|
-
keys: [
|
|
623
|
-
{ pubkey: stakePubkey, isSigner: false, isWritable: true },
|
|
624
|
-
{ pubkey: splitStakePubkey, isSigner: false, isWritable: true },
|
|
625
|
-
{ pubkey: authorizedPubkey, isSigner: true, isWritable: false },
|
|
626
|
-
],
|
|
627
|
-
programId: this.programId,
|
|
628
|
-
data,
|
|
629
|
-
})
|
|
630
|
-
}
|
|
631
|
-
|
|
632
484
|
/**
|
|
633
485
|
* Generate a Transaction that withdraws deactivated Stake tokens.
|
|
634
486
|
*/
|