@exodus/solana-lib 1.0.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/README.md +8 -0
- package/package.json +26 -0
- package/src/encode.js +29 -0
- package/src/fee-data/index.js +1 -0
- package/src/fee-data/solana.js +9 -0
- package/src/helpers/account.js +38 -0
- package/src/helpers/blockhash.js +6 -0
- package/src/helpers/fee-calculator.js +17 -0
- package/src/helpers/instruction.js +46 -0
- package/src/helpers/layout.js +80 -0
- package/src/helpers/message.js +216 -0
- package/src/helpers/nonce-account.js +46 -0
- package/src/helpers/publickey.js +209 -0
- package/src/helpers/shortvec-encoding.js +30 -0
- package/src/helpers/system-program.js +782 -0
- package/src/helpers/sysvar.js +16 -0
- package/src/helpers/transaction.js +593 -0
- package/src/helpers/util/to-buffer.js +9 -0
- package/src/index.js +6 -0
- package/src/keypair.js +32 -0
- package/src/transaction.js +64 -0
- package/src/tx/create-and-sign-tx.js +8 -0
- package/src/tx/create-unsigned-tx.js +21 -0
- package/src/tx/index.js +4 -0
- package/src/tx/parse-unsigned-tx.js +16 -0
- package/src/tx/sign-unsigned-tx.js +25 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import BN from 'bn.js'
|
|
4
|
+
import bs58 from 'bs58'
|
|
5
|
+
import nacl from 'tweetnacl'
|
|
6
|
+
import createHash from 'create-hash'
|
|
7
|
+
|
|
8
|
+
// $FlowFixMe
|
|
9
|
+
let naclLowLevel = nacl.lowlevel
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A public key
|
|
13
|
+
*/
|
|
14
|
+
export class PublicKey {
|
|
15
|
+
_bn: BN
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a new PublicKey object
|
|
19
|
+
*/
|
|
20
|
+
constructor(value: number | string | Buffer | Uint8Array | Array<number>) {
|
|
21
|
+
if (typeof value === 'string') {
|
|
22
|
+
// assume base 58 encoding by default
|
|
23
|
+
const decoded = bs58.decode(value)
|
|
24
|
+
if (decoded.length !== 32) {
|
|
25
|
+
throw new Error(`Invalid public key input`)
|
|
26
|
+
}
|
|
27
|
+
this._bn = new BN(decoded)
|
|
28
|
+
} else {
|
|
29
|
+
this._bn = new BN(value)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (this._bn.byteLength() > 32) {
|
|
33
|
+
throw new Error(`Invalid public key input`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Checks if two publicKeys are equal
|
|
39
|
+
*/
|
|
40
|
+
equals(publicKey: PublicKey): boolean {
|
|
41
|
+
return this._bn.eq(publicKey._bn)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Return the base-58 representation of the public key
|
|
46
|
+
*/
|
|
47
|
+
toBase58(): string {
|
|
48
|
+
return bs58.encode(this.toBuffer())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Return the Buffer representation of the public key
|
|
53
|
+
*/
|
|
54
|
+
toBuffer(): Buffer {
|
|
55
|
+
const b = this._bn.toArrayLike(Buffer)
|
|
56
|
+
if (b.length === 32) {
|
|
57
|
+
return b
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const zeroPad = Buffer.alloc(32)
|
|
61
|
+
b.copy(zeroPad, 32 - b.length)
|
|
62
|
+
return zeroPad
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns a string representation of the public key
|
|
67
|
+
*/
|
|
68
|
+
toString(): string {
|
|
69
|
+
return this.toBase58()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Derive a public key from another key, a seed, and a program ID.
|
|
74
|
+
*/
|
|
75
|
+
static async createWithSeed(
|
|
76
|
+
fromPublicKey: PublicKey,
|
|
77
|
+
seed: string,
|
|
78
|
+
programId: PublicKey
|
|
79
|
+
): Promise<PublicKey> {
|
|
80
|
+
const buffer = Buffer.concat([
|
|
81
|
+
fromPublicKey.toBuffer(),
|
|
82
|
+
Buffer.from(seed),
|
|
83
|
+
programId.toBuffer(),
|
|
84
|
+
])
|
|
85
|
+
const hash = sha256(new Uint8Array(buffer))
|
|
86
|
+
return new PublicKey(Buffer.from(hash, 'hex'))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Derive a program address from seeds and a program ID.
|
|
91
|
+
*/
|
|
92
|
+
static async createProgramAddress(
|
|
93
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
94
|
+
programId: PublicKey
|
|
95
|
+
): Promise<PublicKey> {
|
|
96
|
+
let buffer = Buffer.alloc(0)
|
|
97
|
+
seeds.forEach(function(seed) {
|
|
98
|
+
buffer = Buffer.concat([buffer, Buffer.from(seed)])
|
|
99
|
+
})
|
|
100
|
+
buffer = Buffer.concat([buffer, programId.toBuffer(), Buffer.from('ProgramDerivedAddress')])
|
|
101
|
+
let hash = sha256(new Uint8Array(buffer))
|
|
102
|
+
let publicKeyBytes = new BN(hash, 16).toArray(null, 32)
|
|
103
|
+
if (isOnCurve(publicKeyBytes)) {
|
|
104
|
+
throw new Error(`Invalid seeds, address must fall off the curve`)
|
|
105
|
+
}
|
|
106
|
+
return new PublicKey(publicKeyBytes)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Find a valid program address
|
|
111
|
+
*
|
|
112
|
+
* Valid program addresses must fall off the ed25519 curve. This function
|
|
113
|
+
* iterates a nonce until it finds one that when combined with the seeds
|
|
114
|
+
* results in a valid program address.
|
|
115
|
+
*/
|
|
116
|
+
static async findProgramAddress(
|
|
117
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
118
|
+
programId: PublicKey
|
|
119
|
+
): Promise {
|
|
120
|
+
let nonce = 255
|
|
121
|
+
let address
|
|
122
|
+
while (nonce !== 0) {
|
|
123
|
+
try {
|
|
124
|
+
const seedsWithNonce = seeds.concat(Buffer.from([nonce]))
|
|
125
|
+
address = await this.createProgramAddress(seedsWithNonce, programId)
|
|
126
|
+
} catch (err) {
|
|
127
|
+
nonce--
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
return [address, nonce]
|
|
131
|
+
}
|
|
132
|
+
throw new Error(`Unable to find a viable program address nonce`)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check that a pubkey is on the curve.
|
|
137
|
+
// This function and its dependents were sourced from:
|
|
138
|
+
// https://github.com/dchest/tweetnacl-js/blob/f1ec050ceae0861f34280e62498b1d3ed9c350c6/nacl.js#L792
|
|
139
|
+
function isOnCurve(p) {
|
|
140
|
+
var r = [naclLowLevel.gf(), naclLowLevel.gf(), naclLowLevel.gf(), naclLowLevel.gf()]
|
|
141
|
+
|
|
142
|
+
var t = naclLowLevel.gf()
|
|
143
|
+
var chk = naclLowLevel.gf()
|
|
144
|
+
var num = naclLowLevel.gf()
|
|
145
|
+
var den = naclLowLevel.gf()
|
|
146
|
+
var den2 = naclLowLevel.gf()
|
|
147
|
+
var den4 = naclLowLevel.gf()
|
|
148
|
+
var den6 = naclLowLevel.gf()
|
|
149
|
+
|
|
150
|
+
naclLowLevel.set25519(r[2], gf1)
|
|
151
|
+
naclLowLevel.unpack25519(r[1], p)
|
|
152
|
+
naclLowLevel.S(num, r[1])
|
|
153
|
+
naclLowLevel.M(den, num, naclLowLevel.D)
|
|
154
|
+
naclLowLevel.Z(num, num, r[2])
|
|
155
|
+
naclLowLevel.A(den, r[2], den)
|
|
156
|
+
|
|
157
|
+
naclLowLevel.S(den2, den)
|
|
158
|
+
naclLowLevel.S(den4, den2)
|
|
159
|
+
naclLowLevel.M(den6, den4, den2)
|
|
160
|
+
naclLowLevel.M(t, den6, num)
|
|
161
|
+
naclLowLevel.M(t, t, den)
|
|
162
|
+
|
|
163
|
+
naclLowLevel.pow2523(t, t)
|
|
164
|
+
naclLowLevel.M(t, t, num)
|
|
165
|
+
naclLowLevel.M(t, t, den)
|
|
166
|
+
naclLowLevel.M(t, t, den)
|
|
167
|
+
naclLowLevel.M(r[0], t, den)
|
|
168
|
+
|
|
169
|
+
naclLowLevel.S(chk, r[0])
|
|
170
|
+
naclLowLevel.M(chk, chk, den)
|
|
171
|
+
if (neq25519(chk, num)) naclLowLevel.M(r[0], r[0], I)
|
|
172
|
+
|
|
173
|
+
naclLowLevel.S(chk, r[0])
|
|
174
|
+
naclLowLevel.M(chk, chk, den)
|
|
175
|
+
if (neq25519(chk, num)) return 0
|
|
176
|
+
return 1
|
|
177
|
+
}
|
|
178
|
+
let gf1 = naclLowLevel.gf([1])
|
|
179
|
+
let I = naclLowLevel.gf([
|
|
180
|
+
0xa0b0,
|
|
181
|
+
0x4a0e,
|
|
182
|
+
0x1b27,
|
|
183
|
+
0xc4ee,
|
|
184
|
+
0xe478,
|
|
185
|
+
0xad2f,
|
|
186
|
+
0x1806,
|
|
187
|
+
0x2f43,
|
|
188
|
+
0xd7a7,
|
|
189
|
+
0x3dfb,
|
|
190
|
+
0x0099,
|
|
191
|
+
0x2b4d,
|
|
192
|
+
0xdf0b,
|
|
193
|
+
0x4fc1,
|
|
194
|
+
0x2480,
|
|
195
|
+
0x2b83,
|
|
196
|
+
])
|
|
197
|
+
function neq25519(a, b) {
|
|
198
|
+
var c = new Uint8Array(32)
|
|
199
|
+
var d = new Uint8Array(32)
|
|
200
|
+
naclLowLevel.pack25519(c, a)
|
|
201
|
+
naclLowLevel.pack25519(d, b)
|
|
202
|
+
return naclLowLevel.crypto_verify_32(c, 0, d, 0)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function sha256(data): string {
|
|
206
|
+
const hash = createHash('sha256')
|
|
207
|
+
hash.update(data)
|
|
208
|
+
return hash.digest('hex')
|
|
209
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
export function decodeLength(bytes: Array<number>): number {
|
|
4
|
+
let len = 0
|
|
5
|
+
let size = 0
|
|
6
|
+
for (;;) {
|
|
7
|
+
let elem = bytes.shift()
|
|
8
|
+
len |= (elem & 0x7f) << (size * 7)
|
|
9
|
+
size += 1
|
|
10
|
+
if ((elem & 0x80) === 0) {
|
|
11
|
+
break
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return len
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function encodeLength(bytes: Array<number>, len: number) {
|
|
18
|
+
let remLen = len
|
|
19
|
+
for (;;) {
|
|
20
|
+
let elem = remLen & 0x7f
|
|
21
|
+
remLen >>= 7
|
|
22
|
+
if (remLen === 0) {
|
|
23
|
+
bytes.push(elem)
|
|
24
|
+
break
|
|
25
|
+
} else {
|
|
26
|
+
elem |= 0x80
|
|
27
|
+
bytes.push(elem)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|