@exodus/solana-lib 1.2.3 → 1.2.5
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 +5 -5
- package/src/constants.js +3 -2
- package/src/encode.js +2 -3
- package/src/helpers/spl-token.js +108 -0
- package/src/{helpers.js → helpers/tokenTransfer.js} +8 -19
- package/src/tokens.js +4 -17
- package/src/transaction.js +22 -13
- package/src/tx/create-unsigned-tx.js +10 -0
- package/src/tx/parse-unsigned-tx.js +15 -1
- package/src/tx/sign-unsigned-tx.js +14 -1
- package/src/vendor/account.js +38 -0
- package/src/vendor/index.js +8 -0
- package/src/vendor/instruction.js +46 -0
- package/src/vendor/message.js +216 -0
- package/src/vendor/nonce-account.js +46 -0
- package/src/vendor/publickey.js +192 -0
- package/src/vendor/system-program.js +782 -0
- package/src/vendor/sysvar.js +16 -0
- package/src/vendor/transaction.js +594 -0
- package/src/vendor/utils/blockhash.js +6 -0
- package/src/vendor/utils/fee-calculator.js +17 -0
- package/src/vendor/utils/layout.js +80 -0
- package/src/vendor/utils/shortvec-encoding.js +30 -0
- package/src/vendor/utils/to-buffer.js +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Exodus internal Solana low-level library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@exodus/asset-lib": "^3.4.3",
|
|
17
|
-
"@exodus/assets": "^8.0.
|
|
17
|
+
"@exodus/assets": "^8.0.2",
|
|
18
|
+
"@exodus/buffer-layout": "^1.2.0-exodus1",
|
|
18
19
|
"@exodus/models": "^8.4.0",
|
|
19
|
-
"@exodus/solana-spl-token": "^0.0.13-exodus2",
|
|
20
|
-
"@exodus/solana-web3.js": "^0.87.1-exodus4",
|
|
21
20
|
"bn.js": "~4.11.0",
|
|
22
21
|
"bs58": "~4.0.1",
|
|
22
|
+
"create-hash": "~1.1.3",
|
|
23
23
|
"tweetnacl": "^1.0.3"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "791e305a718246460d5ac93ed2eb7808955c0f5d"
|
|
26
26
|
}
|
package/src/constants.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { PublicKey, SystemProgram } from '
|
|
2
|
-
export { TOKEN_PROGRAM_ID } from '@exodus/solana-spl-token'
|
|
1
|
+
import { PublicKey, SystemProgram } from './vendor'
|
|
3
2
|
|
|
4
3
|
export const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey(
|
|
5
4
|
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
|
|
6
5
|
)
|
|
7
6
|
export const SYSTEM_PROGRAM_ID = SystemProgram.programId
|
|
7
|
+
|
|
8
|
+
export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')
|
package/src/encode.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
import { PublicKey } from '
|
|
3
|
-
import { TOKEN_PROGRAM_ID } from '
|
|
4
|
-
import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID } from './constants'
|
|
2
|
+
import { PublicKey } from './vendor'
|
|
3
|
+
import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, TOKEN_PROGRAM_ID } from './constants'
|
|
5
4
|
import { getPublicKey } from './keypair'
|
|
6
5
|
import bs58 from 'bs58'
|
|
7
6
|
import BN from 'bn.js'
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import BN from 'bn.js'
|
|
3
|
+
import * as BufferLayout from '@exodus/buffer-layout'
|
|
4
|
+
import { Account, PublicKey, TransactionInstruction } from '../vendor'
|
|
5
|
+
import * as Layout from '../vendor/utils/layout'
|
|
6
|
+
|
|
7
|
+
// Extracted from https://github.com/ExodusMovement/solana-spl-token/blob/master/src/index.js#L263
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 64-bit value
|
|
11
|
+
*/
|
|
12
|
+
export class U64 extends BN {
|
|
13
|
+
/**
|
|
14
|
+
* Convert to Buffer representation
|
|
15
|
+
*/
|
|
16
|
+
toBuffer(): typeof Buffer {
|
|
17
|
+
const a = super.toArray().reverse()
|
|
18
|
+
const b = Buffer.from(a)
|
|
19
|
+
if (b.length === 8) {
|
|
20
|
+
return b
|
|
21
|
+
}
|
|
22
|
+
assert(b.length < 8, 'u64 too large')
|
|
23
|
+
|
|
24
|
+
const zeroPad = Buffer.alloc(8)
|
|
25
|
+
b.copy(zeroPad)
|
|
26
|
+
return zeroPad
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Construct a u64 from Buffer representation
|
|
31
|
+
*/
|
|
32
|
+
static fromBuffer(buffer: typeof Buffer): U64 {
|
|
33
|
+
assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`)
|
|
34
|
+
return new U64(
|
|
35
|
+
[...buffer]
|
|
36
|
+
.reverse()
|
|
37
|
+
.map((i) => `00${i.toString(16)}`.slice(-2))
|
|
38
|
+
.join(''),
|
|
39
|
+
16
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const u64 = U64 // alias
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* An ERC20-like Token
|
|
48
|
+
*/
|
|
49
|
+
export class Token {
|
|
50
|
+
/**
|
|
51
|
+
* Construct a Transfer instruction
|
|
52
|
+
*
|
|
53
|
+
* @param programId SPL Token program account
|
|
54
|
+
* @param source Source account
|
|
55
|
+
* @param destination Destination account
|
|
56
|
+
* @param owner Owner of the source account
|
|
57
|
+
* @param multiSigners Signing accounts if `authority` is a multiSig
|
|
58
|
+
* @param amount Number of tokens to transfer
|
|
59
|
+
*/
|
|
60
|
+
static createTransferInstruction(
|
|
61
|
+
programId: PublicKey,
|
|
62
|
+
source: PublicKey,
|
|
63
|
+
destination: PublicKey,
|
|
64
|
+
owner: PublicKey,
|
|
65
|
+
multiSigners: Array<Account>,
|
|
66
|
+
amount: number | u64
|
|
67
|
+
): TransactionInstruction {
|
|
68
|
+
const dataLayout = BufferLayout.struct([
|
|
69
|
+
BufferLayout.u8('instruction'),
|
|
70
|
+
Layout.uint64('amount'),
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
const data = Buffer.alloc(dataLayout.span)
|
|
74
|
+
dataLayout.encode(
|
|
75
|
+
{
|
|
76
|
+
instruction: 3, // Transfer instruction
|
|
77
|
+
amount: new U64(amount).toBuffer(),
|
|
78
|
+
},
|
|
79
|
+
data
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
let keys = [
|
|
83
|
+
{ pubkey: source, isSigner: false, isWritable: true },
|
|
84
|
+
{ pubkey: destination, isSigner: false, isWritable: true },
|
|
85
|
+
]
|
|
86
|
+
if (multiSigners.length === 0) {
|
|
87
|
+
keys.push({
|
|
88
|
+
pubkey: owner,
|
|
89
|
+
isSigner: true,
|
|
90
|
+
isWritable: false,
|
|
91
|
+
})
|
|
92
|
+
} else {
|
|
93
|
+
keys.push({ pubkey: owner, isSigner: false, isWritable: false })
|
|
94
|
+
multiSigners.forEach((signer) =>
|
|
95
|
+
keys.push({
|
|
96
|
+
pubkey: signer.publicKey,
|
|
97
|
+
isSigner: true,
|
|
98
|
+
isWritable: false,
|
|
99
|
+
})
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
return new TransactionInstruction({
|
|
103
|
+
keys,
|
|
104
|
+
programId: programId,
|
|
105
|
+
data,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
SYSVAR_RENT_PUBKEY,
|
|
6
|
-
} from '@exodus/solana-web3.js'
|
|
7
|
-
import { Token, TOKEN_PROGRAM_ID } from '@exodus/solana-spl-token'
|
|
8
|
-
import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID } from './constants'
|
|
9
|
-
import { findAssociatedTokenAddress } from './encode'
|
|
1
|
+
import { Token } from './spl-token'
|
|
2
|
+
import { PublicKey, TransactionInstruction, SystemProgram, SYSVAR_RENT_PUBKEY } from '../vendor'
|
|
3
|
+
import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'
|
|
4
|
+
import { findAssociatedTokenAddress } from '../encode'
|
|
10
5
|
|
|
11
6
|
// https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/associatedToken.ts#L59
|
|
12
7
|
export const createAssociatedTokenAccount = (
|
|
@@ -57,17 +52,11 @@ function createIx(
|
|
|
57
52
|
})
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
// https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/editing.ts#
|
|
61
|
-
export const createTokenTransferInstruction = (
|
|
62
|
-
owner,
|
|
63
|
-
fromTokenAddress,
|
|
64
|
-
tokenMintAddress,
|
|
65
|
-
to,
|
|
66
|
-
amount
|
|
67
|
-
) => {
|
|
55
|
+
// https://github.com/paul-schaaf/spl-token-ui/blob/main/src/solana/token/editing.ts#L211
|
|
56
|
+
export const createTokenTransferInstruction = (owner, fromTokenAddress, to, amount) => {
|
|
68
57
|
const sourcePubkey = new PublicKey(fromTokenAddress) // the token ADDRESS needed!
|
|
69
|
-
const destinationPubkey = new PublicKey(
|
|
70
|
-
console.log(`destination
|
|
58
|
+
const destinationPubkey = new PublicKey(to)
|
|
59
|
+
console.log(`destination token address: ${destinationPubkey.toBase58()}`)
|
|
71
60
|
const ownerAccountOrWalletPublicKey = new PublicKey(owner) // the only native SOL address
|
|
72
61
|
|
|
73
62
|
const transferIx = Token.createTransferInstruction(
|
package/src/tokens.js
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
//
|
|
1
|
+
// adapted from https://github.com/project-serum/spl-token-wallet/blob/master/src/utils/tokens/names.js
|
|
2
2
|
|
|
3
3
|
const TOKENS = [
|
|
4
4
|
{
|
|
5
5
|
mintAddress: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt',
|
|
6
|
-
tokenName: '
|
|
6
|
+
tokenName: 'serum',
|
|
7
|
+
tokenProperName: 'Serum',
|
|
7
8
|
tokenSymbol: 'SRM',
|
|
8
9
|
},
|
|
9
|
-
|
|
10
|
-
tokenSymbol: 'BTC',
|
|
11
|
-
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
|
12
|
-
tokenName: 'Wrapped Bitcoin',
|
|
13
|
-
icon:
|
|
14
|
-
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/bitcoin/info/logo.png',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
tokenSymbol: 'USDC',
|
|
18
|
-
mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
19
|
-
tokenName: 'USD Coin',
|
|
20
|
-
icon:
|
|
21
|
-
'https://raw.githubusercontent.com/trustwallet/assets/f3ffd0b9ae2165336279ce2f8db1981a55ce30f8/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
|
|
22
|
-
},
|
|
23
|
-
// ... TODO: do we want to add decimals for every token? (Serum SRM is 6)
|
|
10
|
+
// ....
|
|
24
11
|
]
|
|
25
12
|
|
|
26
13
|
export default TOKENS
|
package/src/transaction.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import assert from 'assert'
|
|
3
3
|
|
|
4
|
-
import { Account, SystemProgram, Transaction, PublicKey } from '@exodus/solana-web3.js'
|
|
5
4
|
import { getKeyPairFromPrivateKey } from './keypair'
|
|
6
|
-
import {
|
|
5
|
+
import { findAssociatedTokenAddress } from './encode'
|
|
6
|
+
import {
|
|
7
|
+
createAssociatedTokenAccount,
|
|
8
|
+
createTokenTransferInstruction,
|
|
9
|
+
} from './helpers/tokenTransfer'
|
|
10
|
+
import { PublicKey, Account, Transaction, SystemProgram } from './vendor'
|
|
7
11
|
import TOKENS from './tokens'
|
|
8
12
|
import bs58 from 'bs58'
|
|
9
13
|
|
|
@@ -15,7 +19,8 @@ class Tx {
|
|
|
15
19
|
recentBlockhash,
|
|
16
20
|
// fee, // (Fee per Signature: 5000 lamports)
|
|
17
21
|
// Tokens related:
|
|
18
|
-
|
|
22
|
+
tokenName,
|
|
23
|
+
destinationAddressType,
|
|
19
24
|
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
20
25
|
fromTokenAddresses, // sender token addresses
|
|
21
26
|
} = {}) {
|
|
@@ -24,7 +29,11 @@ class Tx {
|
|
|
24
29
|
assert(amount, 'amount is required')
|
|
25
30
|
assert(typeof amount === 'number', 'amount must be a number')
|
|
26
31
|
assert(recentBlockhash, 'recentBlockhash is required')
|
|
27
|
-
if (
|
|
32
|
+
if (tokenName) {
|
|
33
|
+
assert(
|
|
34
|
+
typeof destinationAddressType !== 'undefined',
|
|
35
|
+
'destinationAddressType is required when sending tokens'
|
|
36
|
+
)
|
|
28
37
|
assert(
|
|
29
38
|
typeof isAssociatedTokenAccountActive !== 'undefined',
|
|
30
39
|
'isAssociatedTokenAccountActive is required when sending tokens'
|
|
@@ -32,13 +41,14 @@ class Tx {
|
|
|
32
41
|
assert(Array.isArray(fromTokenAddresses), 'fromTokenAddresses Array is required')
|
|
33
42
|
}
|
|
34
43
|
|
|
35
|
-
const token = TOKENS.find(({
|
|
44
|
+
const token = TOKENS.find(({ tokenName: name }) => name === tokenName)
|
|
36
45
|
this.txObj = {
|
|
37
46
|
from,
|
|
38
47
|
to,
|
|
39
48
|
amount,
|
|
40
49
|
recentBlockhash,
|
|
41
50
|
token,
|
|
51
|
+
destinationAddressType,
|
|
42
52
|
isAssociatedTokenAccountActive,
|
|
43
53
|
fromTokenAddresses,
|
|
44
54
|
}
|
|
@@ -71,14 +81,18 @@ class Tx {
|
|
|
71
81
|
amount,
|
|
72
82
|
recentBlockhash,
|
|
73
83
|
token,
|
|
84
|
+
destinationAddressType,
|
|
74
85
|
isAssociatedTokenAccountActive,
|
|
75
86
|
fromTokenAddresses,
|
|
76
87
|
}) {
|
|
77
88
|
this.transaction = new Transaction({
|
|
78
89
|
recentBlockhash,
|
|
79
90
|
})
|
|
91
|
+
const isUnknown = destinationAddressType === null
|
|
92
|
+
const isSOLaddress = destinationAddressType === 'solana'
|
|
80
93
|
// crete account instruction
|
|
81
|
-
if (
|
|
94
|
+
if (isUnknown) throw new Error('Destination SOL balance cannot be zero (address not active)') // cannot initialize without knowing the owner
|
|
95
|
+
if (isSOLaddress && !isAssociatedTokenAccountActive)
|
|
82
96
|
this.transaction.add(createAssociatedTokenAccount(from, token.mintAddress, to))
|
|
83
97
|
|
|
84
98
|
let amountLeft = amount
|
|
@@ -97,15 +111,10 @@ class Tx {
|
|
|
97
111
|
amountLeft -= amountToSend
|
|
98
112
|
}
|
|
99
113
|
|
|
114
|
+
const dest = isSOLaddress ? findAssociatedTokenAddress(to, token.mintAddress) : to
|
|
100
115
|
// add transfer token instruction
|
|
101
116
|
this.transaction.add(
|
|
102
|
-
createTokenTransferInstruction(
|
|
103
|
-
from,
|
|
104
|
-
tokenAccountAddress,
|
|
105
|
-
token.mintAddress,
|
|
106
|
-
to,
|
|
107
|
-
amountToSend
|
|
108
|
-
)
|
|
117
|
+
createTokenTransferInstruction(from, tokenAccountAddress, dest, amountToSend)
|
|
109
118
|
)
|
|
110
119
|
}
|
|
111
120
|
|
|
@@ -6,6 +6,11 @@ export function createUnsignedTx({
|
|
|
6
6
|
to,
|
|
7
7
|
amount,
|
|
8
8
|
recentBlockhash,
|
|
9
|
+
// Tokens related:
|
|
10
|
+
tokenName,
|
|
11
|
+
destinationAddressType,
|
|
12
|
+
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
13
|
+
fromTokenAddresses, // sender token addresses
|
|
9
14
|
}: ParsedTransaction): UnsignedTransaction {
|
|
10
15
|
return {
|
|
11
16
|
txData: {
|
|
@@ -13,6 +18,11 @@ export function createUnsignedTx({
|
|
|
13
18
|
to,
|
|
14
19
|
amount: amount.toBase().toNumber(),
|
|
15
20
|
recentBlockhash,
|
|
21
|
+
// Tokens related:
|
|
22
|
+
tokenName,
|
|
23
|
+
destinationAddressType,
|
|
24
|
+
isAssociatedTokenAccountActive,
|
|
25
|
+
fromTokenAddresses,
|
|
16
26
|
},
|
|
17
27
|
txMeta: {
|
|
18
28
|
assetName: asset.name,
|
|
@@ -3,7 +3,16 @@ import type { UnsignedTransaction, ParsedTransaction } from '@exodus/models/lib/
|
|
|
3
3
|
|
|
4
4
|
export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransaction {
|
|
5
5
|
const asset = assets.solana
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
from,
|
|
8
|
+
to,
|
|
9
|
+
recentBlockhash,
|
|
10
|
+
tokenName,
|
|
11
|
+
destinationAddressType,
|
|
12
|
+
isAssociatedTokenAccountActive,
|
|
13
|
+
fromTokenAddresses,
|
|
14
|
+
...txData
|
|
15
|
+
} = unsignedTx.txData
|
|
7
16
|
|
|
8
17
|
const amount = asset.currency.baseUnit(txData.amount)
|
|
9
18
|
return {
|
|
@@ -12,5 +21,10 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
12
21
|
to,
|
|
13
22
|
amount,
|
|
14
23
|
recentBlockhash,
|
|
24
|
+
// token related
|
|
25
|
+
tokenName,
|
|
26
|
+
destinationAddressType,
|
|
27
|
+
isAssociatedTokenAccountActive,
|
|
28
|
+
fromTokenAddresses,
|
|
15
29
|
}
|
|
16
30
|
}
|
|
@@ -6,7 +6,16 @@ export function signUnsignedTx(
|
|
|
6
6
|
unsignedTx: UnsignedTransaction,
|
|
7
7
|
privateKey: Buffer
|
|
8
8
|
): SignedTransaction {
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
from,
|
|
11
|
+
to,
|
|
12
|
+
amount,
|
|
13
|
+
recentBlockhash,
|
|
14
|
+
tokenName,
|
|
15
|
+
destinationAddressType,
|
|
16
|
+
isAssociatedTokenAccountActive,
|
|
17
|
+
fromTokenAddresses,
|
|
18
|
+
} = unsignedTx.txData
|
|
10
19
|
|
|
11
20
|
const asset = assets.solana
|
|
12
21
|
const tx = new Transaction({
|
|
@@ -14,6 +23,10 @@ export function signUnsignedTx(
|
|
|
14
23
|
to,
|
|
15
24
|
amount: asset.currency.baseUnit(amount).toNumber(),
|
|
16
25
|
recentBlockhash,
|
|
26
|
+
tokenName,
|
|
27
|
+
destinationAddressType,
|
|
28
|
+
isAssociatedTokenAccountActive,
|
|
29
|
+
fromTokenAddresses,
|
|
17
30
|
})
|
|
18
31
|
|
|
19
32
|
// sign plain tx
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { KeyPair } from 'tweetnacl'
|
|
3
|
+
import { PublicKey } from './publickey'
|
|
4
|
+
import { getKeyPairFromPrivateKey } from '../keypair'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An account key pair (public and secret keys).
|
|
8
|
+
*/
|
|
9
|
+
export class Account {
|
|
10
|
+
_keypair: KeyPair
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a new Account object
|
|
14
|
+
*
|
|
15
|
+
* @param secretKey Secret key for the account
|
|
16
|
+
*/
|
|
17
|
+
constructor(secretKey: Buffer | Uint8Array | Array<number>) {
|
|
18
|
+
if (secretKey) {
|
|
19
|
+
this._keypair = getKeyPairFromPrivateKey(Buffer.from(secretKey, 'hex'))
|
|
20
|
+
} else {
|
|
21
|
+
throw new Error('Please provide a secretKey')
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The public key for this account
|
|
27
|
+
*/
|
|
28
|
+
get publicKey(): PublicKey {
|
|
29
|
+
return new PublicKey(this._keypair.publicKey)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The **unencrypted** secret key for this account
|
|
34
|
+
*/
|
|
35
|
+
get secretKey(): Buffer {
|
|
36
|
+
return this._keypair.secretKey
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import * as BufferLayout from '@exodus/buffer-layout'
|
|
4
|
+
|
|
5
|
+
import * as Layout from './utils/layout'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} InstructionType
|
|
9
|
+
* @property (index} The Instruction index (from solana upstream program)
|
|
10
|
+
* @property (BufferLayout} The BufferLayout to use to build data
|
|
11
|
+
*/
|
|
12
|
+
export type InstructionType = {|
|
|
13
|
+
index: number,
|
|
14
|
+
layout: typeof BufferLayout,
|
|
15
|
+
|}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Populate a buffer of instruction data using an InstructionType
|
|
19
|
+
*/
|
|
20
|
+
export function encodeData(type: InstructionType, fields: Object): Buffer {
|
|
21
|
+
const allocLength = type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields)
|
|
22
|
+
const data = Buffer.alloc(allocLength)
|
|
23
|
+
const layoutFields = Object.assign({ instruction: type.index }, fields)
|
|
24
|
+
type.layout.encode(layoutFields, data)
|
|
25
|
+
return data
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Decode instruction data buffer using an InstructionType
|
|
30
|
+
*/
|
|
31
|
+
export function decodeData(type: InstructionType, buffer: Buffer): Object {
|
|
32
|
+
let data
|
|
33
|
+
try {
|
|
34
|
+
data = type.layout.decode(buffer)
|
|
35
|
+
} catch (err) {
|
|
36
|
+
throw new Error('invalid instruction; ' + err)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (data.instruction !== type.index) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return data
|
|
46
|
+
}
|