@exodus/solana-lib 1.2.29 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/constants.js +4 -0
- package/src/helpers/metadata-schema.js +40 -41
- package/src/helpers/spl-token.js +30 -0
- package/src/index.js +6 -2
- package/src/transaction.js +1 -9
- package/src/tx/create-unsigned-tx.js +0 -2
- package/src/tx/index.js +1 -0
- package/src/tx/parse-unsigned-tx.js +0 -2
- package/src/tx/sign-unsigned-tx.js +0 -2
- package/src/tx/simulate-and-sign-tx.js +77 -0
- package/src/tokens.js +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Exodus internal Solana low-level library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
"lodash": "^4.17.11",
|
|
26
26
|
"tweetnacl": "^1.0.3"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "49f3f78ac41acaf405e2849cccb2f9ecd0060424"
|
|
29
29
|
}
|
package/src/constants.js
CHANGED
|
@@ -3,71 +3,71 @@
|
|
|
3
3
|
import bs58 from 'bs58'
|
|
4
4
|
import { BinaryReader, BinaryWriter } from 'borsh'
|
|
5
5
|
|
|
6
|
-
BinaryReader.prototype.readPubkeyAsString = function
|
|
6
|
+
BinaryReader.prototype.readPubkeyAsString = function() {
|
|
7
7
|
const reader = this
|
|
8
8
|
const array = reader.readFixedArray(32)
|
|
9
9
|
return bs58.encode(array)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
BinaryWriter.prototype.writePubkeyAsString = function
|
|
12
|
+
BinaryWriter.prototype.writePubkeyAsString = function(value) {
|
|
13
13
|
const writer = this
|
|
14
14
|
writer.writeFixedArray(bs58.decode(value))
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
class Data {
|
|
18
18
|
constructor(args) {
|
|
19
|
-
this.name = args.name
|
|
20
|
-
this.symbol = args.symbol
|
|
21
|
-
this.uri = args.uri
|
|
22
|
-
this.sellerFeeBasisPoints = args.sellerFeeBasisPoints
|
|
23
|
-
this.creators = args.creators
|
|
19
|
+
this.name = args.name
|
|
20
|
+
this.symbol = args.symbol
|
|
21
|
+
this.uri = args.uri
|
|
22
|
+
this.sellerFeeBasisPoints = args.sellerFeeBasisPoints
|
|
23
|
+
this.creators = args.creators
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
class Creator {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
constructor(args) {
|
|
29
|
+
this.address = args.address
|
|
30
|
+
this.verified = args.verified
|
|
31
|
+
this.share = args.share
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
class Metadata {
|
|
36
36
|
constructor(args) {
|
|
37
37
|
this.key = '' // MetadataKey.MetadataV1;
|
|
38
|
-
this.updateAuthority = args.updateAuthority
|
|
39
|
-
this.mint = args.mint
|
|
40
|
-
this.data = args.data
|
|
41
|
-
this.primarySaleHappened = args.primarySaleHappened
|
|
42
|
-
this.isMutable = args.isMutable
|
|
43
|
-
this.editionNonce = args.editionNonce || null
|
|
38
|
+
this.updateAuthority = args.updateAuthority
|
|
39
|
+
this.mint = args.mint
|
|
40
|
+
this.data = args.data
|
|
41
|
+
this.primarySaleHappened = args.primarySaleHappened
|
|
42
|
+
this.isMutable = args.isMutable
|
|
43
|
+
this.editionNonce = args.editionNonce || null
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const METADATA_SCHEMA = new Map([
|
|
48
48
|
[
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
Data,
|
|
50
|
+
{
|
|
51
|
+
kind: 'struct',
|
|
52
|
+
fields: [
|
|
53
|
+
['name', 'string'],
|
|
54
|
+
['symbol', 'string'],
|
|
55
|
+
['uri', 'string'],
|
|
56
|
+
['sellerFeeBasisPoints', 'u16'],
|
|
57
|
+
['creators', { kind: 'option', type: [Creator] }],
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
60
|
],
|
|
61
61
|
[
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
Creator,
|
|
63
|
+
{
|
|
64
|
+
kind: 'struct',
|
|
65
|
+
fields: [
|
|
66
|
+
['address', 'pubkeyAsString'],
|
|
67
|
+
['verified', 'u8'],
|
|
68
|
+
['share', 'u8'],
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
71
|
],
|
|
72
72
|
[
|
|
73
73
|
Metadata,
|
|
@@ -84,10 +84,9 @@ const METADATA_SCHEMA = new Map([
|
|
|
84
84
|
],
|
|
85
85
|
},
|
|
86
86
|
],
|
|
87
|
-
])
|
|
88
|
-
|
|
87
|
+
])
|
|
89
88
|
|
|
90
89
|
module.exports = {
|
|
91
90
|
METADATA_SCHEMA,
|
|
92
|
-
Metadata
|
|
91
|
+
Metadata,
|
|
93
92
|
}
|
package/src/helpers/spl-token.js
CHANGED
|
@@ -43,6 +43,20 @@ export class U64 extends BN {
|
|
|
43
43
|
|
|
44
44
|
const u64 = U64 // alias
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Layout for a public key
|
|
48
|
+
*/
|
|
49
|
+
const publicKey = (property = 'publicKey') => {
|
|
50
|
+
return BufferLayout.blob(32, property)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Layout for a 64bit unsigned value
|
|
55
|
+
*/
|
|
56
|
+
const uint64 = (property = 'uint64') => {
|
|
57
|
+
return BufferLayout.blob(8, property)
|
|
58
|
+
}
|
|
59
|
+
|
|
46
60
|
/**
|
|
47
61
|
* An ERC20-like Token
|
|
48
62
|
*/
|
|
@@ -105,4 +119,20 @@ export class Token {
|
|
|
105
119
|
data,
|
|
106
120
|
})
|
|
107
121
|
}
|
|
122
|
+
|
|
123
|
+
static decode(data: string) {
|
|
124
|
+
return BufferLayout.struct([
|
|
125
|
+
publicKey('mint'),
|
|
126
|
+
publicKey('owner'),
|
|
127
|
+
uint64('amount'),
|
|
128
|
+
BufferLayout.u32('delegateOption'),
|
|
129
|
+
publicKey('delegate'),
|
|
130
|
+
BufferLayout.u8('state'),
|
|
131
|
+
BufferLayout.u32('isNativeOption'),
|
|
132
|
+
uint64('isNative'),
|
|
133
|
+
uint64('delegatedAmount'),
|
|
134
|
+
BufferLayout.u32('closeAuthorityOption'),
|
|
135
|
+
publicKey('closeAuthority'),
|
|
136
|
+
]).decode(data)
|
|
137
|
+
}
|
|
108
138
|
}
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,10 @@ export * from './constants'
|
|
|
4
4
|
export * from './encode'
|
|
5
5
|
export * from './keypair'
|
|
6
6
|
export * from './tx'
|
|
7
|
-
export {
|
|
8
|
-
|
|
7
|
+
export {
|
|
8
|
+
StakeInstruction,
|
|
9
|
+
PublicKey,
|
|
10
|
+
Transaction as SolanaWeb3Transaction,
|
|
11
|
+
Message as SolanaWeb3Message,
|
|
12
|
+
} from './vendor'
|
|
9
13
|
export { default as Transaction } from './transaction'
|
package/src/transaction.js
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
} from './vendor'
|
|
23
23
|
import { MagicEdenEscrowProgram } from './magiceden/escrow-program'
|
|
24
24
|
import { SEED, STAKE_PROGRAM_ID } from './constants'
|
|
25
|
-
import TOKENS from './tokens'
|
|
26
25
|
|
|
27
26
|
class Tx {
|
|
28
27
|
constructor({
|
|
@@ -33,7 +32,6 @@ class Tx {
|
|
|
33
32
|
// fee, // (Fee per Signature: 5000 lamports)
|
|
34
33
|
// Tokens related:
|
|
35
34
|
// pass either name or mintAddress, if both, mintAddress has priority
|
|
36
|
-
tokenName,
|
|
37
35
|
tokenMintAddress,
|
|
38
36
|
destinationAddressType,
|
|
39
37
|
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
@@ -44,7 +42,7 @@ class Tx {
|
|
|
44
42
|
assert(amount, 'amount is required')
|
|
45
43
|
assert(typeof amount === 'number', 'amount must be a number')
|
|
46
44
|
assert(recentBlockhash, 'recentBlockhash is required')
|
|
47
|
-
if (
|
|
45
|
+
if (tokenMintAddress) {
|
|
48
46
|
assert(
|
|
49
47
|
typeof destinationAddressType !== 'undefined',
|
|
50
48
|
'destinationAddressType is required when sending tokens'
|
|
@@ -56,12 +54,6 @@ class Tx {
|
|
|
56
54
|
assert(Array.isArray(fromTokenAddresses), 'fromTokenAddresses Array is required')
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
if (tokenName && !tokenMintAddress) {
|
|
60
|
-
const token = TOKENS.find(({ name }) => name === tokenName)
|
|
61
|
-
assert(token, `token with tokenName ${tokenName} not found in tokens list`)
|
|
62
|
-
tokenMintAddress = token.mintAddress
|
|
63
|
-
}
|
|
64
|
-
|
|
65
57
|
this.txObj = {
|
|
66
58
|
from,
|
|
67
59
|
to,
|
|
@@ -8,7 +8,6 @@ export function createUnsignedTx({
|
|
|
8
8
|
fee,
|
|
9
9
|
recentBlockhash,
|
|
10
10
|
// Tokens related:
|
|
11
|
-
tokenName,
|
|
12
11
|
tokenMintAddress,
|
|
13
12
|
destinationAddressType,
|
|
14
13
|
isAssociatedTokenAccountActive, // true when recipient balance !== 0
|
|
@@ -40,7 +39,6 @@ export function createUnsignedTx({
|
|
|
40
39
|
fee: fee.toBase().toNumber(),
|
|
41
40
|
recentBlockhash,
|
|
42
41
|
// Tokens related:
|
|
43
|
-
tokenName,
|
|
44
42
|
tokenMintAddress,
|
|
45
43
|
destinationAddressType,
|
|
46
44
|
isAssociatedTokenAccountActive,
|
package/src/tx/index.js
CHANGED
|
@@ -7,7 +7,6 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
7
7
|
from,
|
|
8
8
|
to,
|
|
9
9
|
recentBlockhash,
|
|
10
|
-
tokenName,
|
|
11
10
|
tokenMintAddress,
|
|
12
11
|
destinationAddressType,
|
|
13
12
|
isAssociatedTokenAccountActive,
|
|
@@ -40,7 +39,6 @@ export function parseUnsignedTx(unsignedTx: UnsignedTransaction): ParsedTransact
|
|
|
40
39
|
fee,
|
|
41
40
|
recentBlockhash,
|
|
42
41
|
// token related
|
|
43
|
-
tokenName,
|
|
44
42
|
tokenMintAddress,
|
|
45
43
|
destinationAddressType,
|
|
46
44
|
isAssociatedTokenAccountActive,
|
|
@@ -12,7 +12,6 @@ export function signUnsignedTx(
|
|
|
12
12
|
amount: unitAmount,
|
|
13
13
|
recentBlockhash,
|
|
14
14
|
// tokens related
|
|
15
|
-
tokenName,
|
|
16
15
|
tokenMintAddress,
|
|
17
16
|
destinationAddressType,
|
|
18
17
|
isAssociatedTokenAccountActive,
|
|
@@ -109,7 +108,6 @@ export function signUnsignedTx(
|
|
|
109
108
|
to,
|
|
110
109
|
amount,
|
|
111
110
|
recentBlockhash,
|
|
112
|
-
tokenName,
|
|
113
111
|
tokenMintAddress,
|
|
114
112
|
destinationAddressType,
|
|
115
113
|
isAssociatedTokenAccountActive,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Token, U64 } from '../helpers/spl-token'
|
|
2
|
+
import { PublicKey } from '../vendor/'
|
|
3
|
+
|
|
4
|
+
export function computeBalance(futureAccountBalance: string, currentAccountBalance: string) {
|
|
5
|
+
return new U64(futureAccountBalance).sub(new U64(currentAccountBalance))
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getTransactionSimulationParams(transaction) {
|
|
9
|
+
const config = {
|
|
10
|
+
encoding: 'base64',
|
|
11
|
+
commitment: 'confirmed',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const accountAddresses = transaction
|
|
15
|
+
.compileMessage()
|
|
16
|
+
.accountKeys.map((account) => account.toString())
|
|
17
|
+
config['accounts'] = {
|
|
18
|
+
encoding: 'base64',
|
|
19
|
+
addresses: accountAddresses,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
config,
|
|
24
|
+
accountAddresses,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isSolAccount = (account) => account === '1111111111111111'
|
|
29
|
+
|
|
30
|
+
export function filterAccountsByOwner(futureAccountsState, accountAddresses, publicKey) {
|
|
31
|
+
const solAccounts = []
|
|
32
|
+
const tokenAccounts = []
|
|
33
|
+
|
|
34
|
+
// Shouldn't happen
|
|
35
|
+
if (futureAccountsState.length !== accountAddresses.length) {
|
|
36
|
+
throw Error('Simulation returning wrong account length')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
futureAccountsState.forEach((futureAccount, index) => {
|
|
40
|
+
try {
|
|
41
|
+
const accountAddress = accountAddresses[index]
|
|
42
|
+
|
|
43
|
+
// Check if it's SOL account (not token)
|
|
44
|
+
if (isSolAccount(futureAccount.owner.toString())) {
|
|
45
|
+
if (accountAddress.toString() === publicKey.toString()) {
|
|
46
|
+
solAccounts.push({
|
|
47
|
+
amount: futureAccount.lamports,
|
|
48
|
+
address: publicKey,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const data = Buffer.from(futureAccount.data[0], 'base64')
|
|
55
|
+
const token = Token.decode(data)
|
|
56
|
+
const owner = new PublicKey(token.owner).toString()
|
|
57
|
+
const amount = U64.fromBuffer(token.amount)
|
|
58
|
+
|
|
59
|
+
// Get tokens by owner using the public key
|
|
60
|
+
if (owner === publicKey.toString()) {
|
|
61
|
+
tokenAccounts.push({
|
|
62
|
+
amount,
|
|
63
|
+
mint: new PublicKey(token.mint).toString(),
|
|
64
|
+
owner: owner,
|
|
65
|
+
address: accountAddress.toString(),
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.warn(error)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
solAccounts,
|
|
75
|
+
tokenAccounts,
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/tokens.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import assets from '@exodus/assets'
|
|
2
|
-
|
|
3
|
-
// tokens info: https://github.com/project-serum/spl-token-wallet/blob/master/src/utils/tokens/names.js
|
|
4
|
-
|
|
5
|
-
const tokens = Object.values(assets)
|
|
6
|
-
.filter((asset) => asset.assetType === 'SOLANA_TOKEN')
|
|
7
|
-
.map((token) => ({
|
|
8
|
-
...token,
|
|
9
|
-
tokenName: token.name, // alias
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
export default tokens
|