@solana/web3.js 0.0.0-next
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/LICENSE +20 -0
- package/README.md +158 -0
- package/lib/index.browser.cjs.js +10062 -0
- package/lib/index.browser.cjs.js.map +1 -0
- package/lib/index.browser.esm.js +9976 -0
- package/lib/index.browser.esm.js.map +1 -0
- package/lib/index.cjs.js +9568 -0
- package/lib/index.cjs.js.map +1 -0
- package/lib/index.d.ts +3311 -0
- package/lib/index.esm.js +9479 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.iife.js +30136 -0
- package/lib/index.iife.js.map +1 -0
- package/lib/index.iife.min.js +40 -0
- package/lib/index.iife.min.js.map +1 -0
- package/package.json +140 -0
- package/src/account.ts +46 -0
- package/src/agent-manager.ts +44 -0
- package/src/blockhash.ts +4 -0
- package/src/bpf-loader-deprecated.ts +5 -0
- package/src/bpf-loader.ts +45 -0
- package/src/connection.ts +4935 -0
- package/src/ed25519-program.ts +157 -0
- package/src/epoch-schedule.ts +102 -0
- package/src/errors.ts +9 -0
- package/src/fee-calculator.ts +16 -0
- package/src/index.ts +31 -0
- package/src/instruction.ts +58 -0
- package/src/keypair.ts +98 -0
- package/src/layout.ts +147 -0
- package/src/loader.ts +236 -0
- package/src/message.ts +271 -0
- package/src/nonce-account.ts +78 -0
- package/src/publickey.ts +296 -0
- package/src/secp256k1-program.ts +229 -0
- package/src/stake-program.ts +923 -0
- package/src/system-program.ts +1007 -0
- package/src/sysvar.ts +37 -0
- package/src/timing.ts +23 -0
- package/src/transaction.ts +808 -0
- package/src/util/assert.ts +8 -0
- package/src/util/borsh-schema.ts +38 -0
- package/src/util/cluster.ts +31 -0
- package/src/util/promise-timeout.ts +14 -0
- package/src/util/send-and-confirm-raw-transaction.ts +46 -0
- package/src/util/send-and-confirm-transaction.ts +50 -0
- package/src/util/shortvec-encoding.ts +28 -0
- package/src/util/sleep.ts +4 -0
- package/src/util/to-buffer.ts +11 -0
- package/src/util/url.ts +18 -0
- package/src/validator-info.ts +106 -0
- package/src/vote-account.ts +236 -0
- package/src/vote-program.ts +413 -0
package/src/publickey.ts
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import BN from 'bn.js';
|
|
2
|
+
import bs58 from 'bs58';
|
|
3
|
+
import {Buffer} from 'buffer';
|
|
4
|
+
import nacl from 'tweetnacl';
|
|
5
|
+
import {sha256} from '@ethersproject/sha2';
|
|
6
|
+
|
|
7
|
+
import {Struct, SOLANA_SCHEMA} from './util/borsh-schema';
|
|
8
|
+
import {toBuffer} from './util/to-buffer';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maximum length of derived pubkey seed
|
|
12
|
+
*/
|
|
13
|
+
export const MAX_SEED_LENGTH = 32;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Value to be converted into public key
|
|
17
|
+
*/
|
|
18
|
+
export type PublicKeyInitData =
|
|
19
|
+
| number
|
|
20
|
+
| string
|
|
21
|
+
| Buffer
|
|
22
|
+
| Uint8Array
|
|
23
|
+
| Array<number>
|
|
24
|
+
| PublicKeyData;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* JSON object representation of PublicKey class
|
|
28
|
+
*/
|
|
29
|
+
export type PublicKeyData = {
|
|
30
|
+
/** @internal */
|
|
31
|
+
_bn: BN;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function isPublicKeyData(value: PublicKeyInitData): value is PublicKeyData {
|
|
35
|
+
return (value as PublicKeyData)._bn !== undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A public key
|
|
40
|
+
*/
|
|
41
|
+
export class PublicKey extends Struct {
|
|
42
|
+
/** @internal */
|
|
43
|
+
_bn: BN;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a new PublicKey object
|
|
47
|
+
* @param value ed25519 public key as buffer or base-58 encoded string
|
|
48
|
+
*/
|
|
49
|
+
constructor(value: PublicKeyInitData) {
|
|
50
|
+
super({});
|
|
51
|
+
if (isPublicKeyData(value)) {
|
|
52
|
+
this._bn = value._bn;
|
|
53
|
+
} else {
|
|
54
|
+
if (typeof value === 'string') {
|
|
55
|
+
// assume base 58 encoding by default
|
|
56
|
+
const decoded = bs58.decode(value);
|
|
57
|
+
if (decoded.length != 32) {
|
|
58
|
+
throw new Error(`Invalid public key input`);
|
|
59
|
+
}
|
|
60
|
+
this._bn = new BN(decoded);
|
|
61
|
+
} else {
|
|
62
|
+
this._bn = new BN(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (this._bn.byteLength() > 32) {
|
|
66
|
+
throw new Error(`Invalid public key input`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Default public key value. (All zeros)
|
|
73
|
+
*/
|
|
74
|
+
static default: PublicKey = new PublicKey('11111111111111111111111111111111');
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Checks if two publicKeys are equal
|
|
78
|
+
*/
|
|
79
|
+
equals(publicKey: PublicKey): boolean {
|
|
80
|
+
return this._bn.eq(publicKey._bn);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Return the base-58 representation of the public key
|
|
85
|
+
*/
|
|
86
|
+
toBase58(): string {
|
|
87
|
+
return bs58.encode(this.toBytes());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
toJSON(): string {
|
|
91
|
+
return this.toBase58();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Return the byte array representation of the public key
|
|
96
|
+
*/
|
|
97
|
+
toBytes(): Uint8Array {
|
|
98
|
+
return this.toBuffer();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Return the Buffer representation of the public key
|
|
103
|
+
*/
|
|
104
|
+
toBuffer(): Buffer {
|
|
105
|
+
const b = this._bn.toArrayLike(Buffer);
|
|
106
|
+
if (b.length === 32) {
|
|
107
|
+
return b;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const zeroPad = Buffer.alloc(32);
|
|
111
|
+
b.copy(zeroPad, 32 - b.length);
|
|
112
|
+
return zeroPad;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Return the base-58 representation of the public key
|
|
117
|
+
*/
|
|
118
|
+
toString(): string {
|
|
119
|
+
return this.toBase58();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Derive a public key from another key, a seed, and a program ID.
|
|
124
|
+
* The program ID will also serve as the owner of the public key, giving
|
|
125
|
+
* it permission to write data to the account.
|
|
126
|
+
*/
|
|
127
|
+
/* eslint-disable require-await */
|
|
128
|
+
static async createWithSeed(
|
|
129
|
+
fromPublicKey: PublicKey,
|
|
130
|
+
seed: string,
|
|
131
|
+
programId: PublicKey,
|
|
132
|
+
): Promise<PublicKey> {
|
|
133
|
+
const buffer = Buffer.concat([
|
|
134
|
+
fromPublicKey.toBuffer(),
|
|
135
|
+
Buffer.from(seed),
|
|
136
|
+
programId.toBuffer(),
|
|
137
|
+
]);
|
|
138
|
+
const hash = sha256(new Uint8Array(buffer)).slice(2);
|
|
139
|
+
return new PublicKey(Buffer.from(hash, 'hex'));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Derive a program address from seeds and a program ID.
|
|
144
|
+
*/
|
|
145
|
+
/* eslint-disable require-await */
|
|
146
|
+
static createProgramAddressSync(
|
|
147
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
148
|
+
programId: PublicKey,
|
|
149
|
+
): PublicKey {
|
|
150
|
+
let buffer = Buffer.alloc(0);
|
|
151
|
+
seeds.forEach(function (seed) {
|
|
152
|
+
if (seed.length > MAX_SEED_LENGTH) {
|
|
153
|
+
throw new TypeError(`Max seed length exceeded`);
|
|
154
|
+
}
|
|
155
|
+
buffer = Buffer.concat([buffer, toBuffer(seed)]);
|
|
156
|
+
});
|
|
157
|
+
buffer = Buffer.concat([
|
|
158
|
+
buffer,
|
|
159
|
+
programId.toBuffer(),
|
|
160
|
+
Buffer.from('ProgramDerivedAddress'),
|
|
161
|
+
]);
|
|
162
|
+
let hash = sha256(new Uint8Array(buffer)).slice(2);
|
|
163
|
+
let publicKeyBytes = new BN(hash, 16).toArray(undefined, 32);
|
|
164
|
+
if (is_on_curve(publicKeyBytes)) {
|
|
165
|
+
throw new Error(`Invalid seeds, address must fall off the curve`);
|
|
166
|
+
}
|
|
167
|
+
return new PublicKey(publicKeyBytes);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Async version of createProgramAddressSync
|
|
172
|
+
* For backwards compatibility
|
|
173
|
+
*/
|
|
174
|
+
/* eslint-disable require-await */
|
|
175
|
+
static async createProgramAddress(
|
|
176
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
177
|
+
programId: PublicKey,
|
|
178
|
+
): Promise<PublicKey> {
|
|
179
|
+
return this.createProgramAddressSync(seeds, programId);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Find a valid program address
|
|
184
|
+
*
|
|
185
|
+
* Valid program addresses must fall off the ed25519 curve. This function
|
|
186
|
+
* iterates a nonce until it finds one that when combined with the seeds
|
|
187
|
+
* results in a valid program address.
|
|
188
|
+
*/
|
|
189
|
+
static findProgramAddressSync(
|
|
190
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
191
|
+
programId: PublicKey,
|
|
192
|
+
): [PublicKey, number] {
|
|
193
|
+
let nonce = 255;
|
|
194
|
+
let address;
|
|
195
|
+
while (nonce != 0) {
|
|
196
|
+
try {
|
|
197
|
+
const seedsWithNonce = seeds.concat(Buffer.from([nonce]));
|
|
198
|
+
address = this.createProgramAddressSync(seedsWithNonce, programId);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
if (err instanceof TypeError) {
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
nonce--;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
return [address, nonce];
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`Unable to find a viable program address nonce`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Async version of findProgramAddressSync
|
|
213
|
+
* For backwards compatibility
|
|
214
|
+
*/
|
|
215
|
+
static async findProgramAddress(
|
|
216
|
+
seeds: Array<Buffer | Uint8Array>,
|
|
217
|
+
programId: PublicKey,
|
|
218
|
+
): Promise<[PublicKey, number]> {
|
|
219
|
+
return this.findProgramAddressSync(seeds, programId);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check that a pubkey is on the ed25519 curve.
|
|
224
|
+
*/
|
|
225
|
+
static isOnCurve(pubkey: Uint8Array): boolean {
|
|
226
|
+
return is_on_curve(pubkey) == 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
SOLANA_SCHEMA.set(PublicKey, {
|
|
231
|
+
kind: 'struct',
|
|
232
|
+
fields: [['_bn', 'u256']],
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// @ts-ignore
|
|
236
|
+
let naclLowLevel = nacl.lowlevel;
|
|
237
|
+
|
|
238
|
+
// Check that a pubkey is on the curve.
|
|
239
|
+
// This function and its dependents were sourced from:
|
|
240
|
+
// https://github.com/dchest/tweetnacl-js/blob/f1ec050ceae0861f34280e62498b1d3ed9c350c6/nacl.js#L792
|
|
241
|
+
function is_on_curve(p: any) {
|
|
242
|
+
var r = [
|
|
243
|
+
naclLowLevel.gf(),
|
|
244
|
+
naclLowLevel.gf(),
|
|
245
|
+
naclLowLevel.gf(),
|
|
246
|
+
naclLowLevel.gf(),
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
var t = naclLowLevel.gf(),
|
|
250
|
+
chk = naclLowLevel.gf(),
|
|
251
|
+
num = naclLowLevel.gf(),
|
|
252
|
+
den = naclLowLevel.gf(),
|
|
253
|
+
den2 = naclLowLevel.gf(),
|
|
254
|
+
den4 = naclLowLevel.gf(),
|
|
255
|
+
den6 = naclLowLevel.gf();
|
|
256
|
+
|
|
257
|
+
naclLowLevel.set25519(r[2], gf1);
|
|
258
|
+
naclLowLevel.unpack25519(r[1], p);
|
|
259
|
+
naclLowLevel.S(num, r[1]);
|
|
260
|
+
naclLowLevel.M(den, num, naclLowLevel.D);
|
|
261
|
+
naclLowLevel.Z(num, num, r[2]);
|
|
262
|
+
naclLowLevel.A(den, r[2], den);
|
|
263
|
+
|
|
264
|
+
naclLowLevel.S(den2, den);
|
|
265
|
+
naclLowLevel.S(den4, den2);
|
|
266
|
+
naclLowLevel.M(den6, den4, den2);
|
|
267
|
+
naclLowLevel.M(t, den6, num);
|
|
268
|
+
naclLowLevel.M(t, t, den);
|
|
269
|
+
|
|
270
|
+
naclLowLevel.pow2523(t, t);
|
|
271
|
+
naclLowLevel.M(t, t, num);
|
|
272
|
+
naclLowLevel.M(t, t, den);
|
|
273
|
+
naclLowLevel.M(t, t, den);
|
|
274
|
+
naclLowLevel.M(r[0], t, den);
|
|
275
|
+
|
|
276
|
+
naclLowLevel.S(chk, r[0]);
|
|
277
|
+
naclLowLevel.M(chk, chk, den);
|
|
278
|
+
if (neq25519(chk, num)) naclLowLevel.M(r[0], r[0], I);
|
|
279
|
+
|
|
280
|
+
naclLowLevel.S(chk, r[0]);
|
|
281
|
+
naclLowLevel.M(chk, chk, den);
|
|
282
|
+
if (neq25519(chk, num)) return 0;
|
|
283
|
+
return 1;
|
|
284
|
+
}
|
|
285
|
+
let gf1 = naclLowLevel.gf([1]);
|
|
286
|
+
let I = naclLowLevel.gf([
|
|
287
|
+
0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7,
|
|
288
|
+
0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83,
|
|
289
|
+
]);
|
|
290
|
+
function neq25519(a: any, b: any) {
|
|
291
|
+
var c = new Uint8Array(32),
|
|
292
|
+
d = new Uint8Array(32);
|
|
293
|
+
naclLowLevel.pack25519(c, a);
|
|
294
|
+
naclLowLevel.pack25519(d, b);
|
|
295
|
+
return naclLowLevel.crypto_verify_32(c, 0, d, 0);
|
|
296
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {Buffer} from 'buffer';
|
|
2
|
+
import * as BufferLayout from '@solana/buffer-layout';
|
|
3
|
+
import secp256k1 from 'secp256k1';
|
|
4
|
+
import sha3 from 'js-sha3';
|
|
5
|
+
|
|
6
|
+
import {PublicKey} from './publickey';
|
|
7
|
+
import {TransactionInstruction} from './transaction';
|
|
8
|
+
import assert from './util/assert';
|
|
9
|
+
import {toBuffer} from './util/to-buffer';
|
|
10
|
+
|
|
11
|
+
const {publicKeyCreate, ecdsaSign} = secp256k1;
|
|
12
|
+
|
|
13
|
+
const PRIVATE_KEY_BYTES = 32;
|
|
14
|
+
const ETHEREUM_ADDRESS_BYTES = 20;
|
|
15
|
+
const PUBLIC_KEY_BYTES = 64;
|
|
16
|
+
const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 11;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Params for creating an secp256k1 instruction using a public key
|
|
20
|
+
*/
|
|
21
|
+
export type CreateSecp256k1InstructionWithPublicKeyParams = {
|
|
22
|
+
publicKey: Buffer | Uint8Array | Array<number>;
|
|
23
|
+
message: Buffer | Uint8Array | Array<number>;
|
|
24
|
+
signature: Buffer | Uint8Array | Array<number>;
|
|
25
|
+
recoveryId: number;
|
|
26
|
+
instructionIndex?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Params for creating an secp256k1 instruction using an Ethereum address
|
|
31
|
+
*/
|
|
32
|
+
export type CreateSecp256k1InstructionWithEthAddressParams = {
|
|
33
|
+
ethAddress: Buffer | Uint8Array | Array<number> | string;
|
|
34
|
+
message: Buffer | Uint8Array | Array<number>;
|
|
35
|
+
signature: Buffer | Uint8Array | Array<number>;
|
|
36
|
+
recoveryId: number;
|
|
37
|
+
instructionIndex?: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Params for creating an secp256k1 instruction using a private key
|
|
42
|
+
*/
|
|
43
|
+
export type CreateSecp256k1InstructionWithPrivateKeyParams = {
|
|
44
|
+
privateKey: Buffer | Uint8Array | Array<number>;
|
|
45
|
+
message: Buffer | Uint8Array | Array<number>;
|
|
46
|
+
instructionIndex?: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const SECP256K1_INSTRUCTION_LAYOUT = BufferLayout.struct<
|
|
50
|
+
Readonly<{
|
|
51
|
+
ethAddress: Uint8Array;
|
|
52
|
+
ethAddressInstructionIndex: number;
|
|
53
|
+
ethAddressOffset: number;
|
|
54
|
+
messageDataOffset: number;
|
|
55
|
+
messageDataSize: number;
|
|
56
|
+
messageInstructionIndex: number;
|
|
57
|
+
numSignatures: number;
|
|
58
|
+
recoveryId: number;
|
|
59
|
+
signature: Uint8Array;
|
|
60
|
+
signatureInstructionIndex: number;
|
|
61
|
+
signatureOffset: number;
|
|
62
|
+
}>
|
|
63
|
+
>([
|
|
64
|
+
BufferLayout.u8('numSignatures'),
|
|
65
|
+
BufferLayout.u16('signatureOffset'),
|
|
66
|
+
BufferLayout.u8('signatureInstructionIndex'),
|
|
67
|
+
BufferLayout.u16('ethAddressOffset'),
|
|
68
|
+
BufferLayout.u8('ethAddressInstructionIndex'),
|
|
69
|
+
BufferLayout.u16('messageDataOffset'),
|
|
70
|
+
BufferLayout.u16('messageDataSize'),
|
|
71
|
+
BufferLayout.u8('messageInstructionIndex'),
|
|
72
|
+
BufferLayout.blob(20, 'ethAddress'),
|
|
73
|
+
BufferLayout.blob(64, 'signature'),
|
|
74
|
+
BufferLayout.u8('recoveryId'),
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
export class Secp256k1Program {
|
|
78
|
+
/**
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
constructor() {}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Public key that identifies the secp256k1 program
|
|
85
|
+
*/
|
|
86
|
+
static programId: PublicKey = new PublicKey(
|
|
87
|
+
'KeccakSecp256k11111111111111111111111111111',
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Construct an Ethereum address from a secp256k1 public key buffer.
|
|
92
|
+
* @param {Buffer} publicKey a 64 byte secp256k1 public key buffer
|
|
93
|
+
*/
|
|
94
|
+
static publicKeyToEthAddress(
|
|
95
|
+
publicKey: Buffer | Uint8Array | Array<number>,
|
|
96
|
+
): Buffer {
|
|
97
|
+
assert(
|
|
98
|
+
publicKey.length === PUBLIC_KEY_BYTES,
|
|
99
|
+
`Public key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
return Buffer.from(
|
|
104
|
+
sha3.keccak_256.update(toBuffer(publicKey)).digest(),
|
|
105
|
+
).slice(-ETHEREUM_ADDRESS_BYTES);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(`Error constructing Ethereum address: ${error}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create an secp256k1 instruction with a public key. The public key
|
|
113
|
+
* must be a buffer that is 64 bytes long.
|
|
114
|
+
*/
|
|
115
|
+
static createInstructionWithPublicKey(
|
|
116
|
+
params: CreateSecp256k1InstructionWithPublicKeyParams,
|
|
117
|
+
): TransactionInstruction {
|
|
118
|
+
const {publicKey, message, signature, recoveryId, instructionIndex} =
|
|
119
|
+
params;
|
|
120
|
+
return Secp256k1Program.createInstructionWithEthAddress({
|
|
121
|
+
ethAddress: Secp256k1Program.publicKeyToEthAddress(publicKey),
|
|
122
|
+
message,
|
|
123
|
+
signature,
|
|
124
|
+
recoveryId,
|
|
125
|
+
instructionIndex,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Create an secp256k1 instruction with an Ethereum address. The address
|
|
131
|
+
* must be a hex string or a buffer that is 20 bytes long.
|
|
132
|
+
*/
|
|
133
|
+
static createInstructionWithEthAddress(
|
|
134
|
+
params: CreateSecp256k1InstructionWithEthAddressParams,
|
|
135
|
+
): TransactionInstruction {
|
|
136
|
+
const {
|
|
137
|
+
ethAddress: rawAddress,
|
|
138
|
+
message,
|
|
139
|
+
signature,
|
|
140
|
+
recoveryId,
|
|
141
|
+
instructionIndex = 0,
|
|
142
|
+
} = params;
|
|
143
|
+
|
|
144
|
+
let ethAddress;
|
|
145
|
+
if (typeof rawAddress === 'string') {
|
|
146
|
+
if (rawAddress.startsWith('0x')) {
|
|
147
|
+
ethAddress = Buffer.from(rawAddress.substr(2), 'hex');
|
|
148
|
+
} else {
|
|
149
|
+
ethAddress = Buffer.from(rawAddress, 'hex');
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
ethAddress = rawAddress;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
assert(
|
|
156
|
+
ethAddress.length === ETHEREUM_ADDRESS_BYTES,
|
|
157
|
+
`Address must be ${ETHEREUM_ADDRESS_BYTES} bytes but received ${ethAddress.length} bytes`,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
|
|
161
|
+
const ethAddressOffset = dataStart;
|
|
162
|
+
const signatureOffset = dataStart + ethAddress.length;
|
|
163
|
+
const messageDataOffset = signatureOffset + signature.length + 1;
|
|
164
|
+
const numSignatures = 1;
|
|
165
|
+
|
|
166
|
+
const instructionData = Buffer.alloc(
|
|
167
|
+
SECP256K1_INSTRUCTION_LAYOUT.span + message.length,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
SECP256K1_INSTRUCTION_LAYOUT.encode(
|
|
171
|
+
{
|
|
172
|
+
numSignatures,
|
|
173
|
+
signatureOffset,
|
|
174
|
+
signatureInstructionIndex: instructionIndex,
|
|
175
|
+
ethAddressOffset,
|
|
176
|
+
ethAddressInstructionIndex: instructionIndex,
|
|
177
|
+
messageDataOffset,
|
|
178
|
+
messageDataSize: message.length,
|
|
179
|
+
messageInstructionIndex: instructionIndex,
|
|
180
|
+
signature: toBuffer(signature),
|
|
181
|
+
ethAddress: toBuffer(ethAddress),
|
|
182
|
+
recoveryId,
|
|
183
|
+
},
|
|
184
|
+
instructionData,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span);
|
|
188
|
+
|
|
189
|
+
return new TransactionInstruction({
|
|
190
|
+
keys: [],
|
|
191
|
+
programId: Secp256k1Program.programId,
|
|
192
|
+
data: instructionData,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Create an secp256k1 instruction with a private key. The private key
|
|
198
|
+
* must be a buffer that is 32 bytes long.
|
|
199
|
+
*/
|
|
200
|
+
static createInstructionWithPrivateKey(
|
|
201
|
+
params: CreateSecp256k1InstructionWithPrivateKeyParams,
|
|
202
|
+
): TransactionInstruction {
|
|
203
|
+
const {privateKey: pkey, message, instructionIndex} = params;
|
|
204
|
+
|
|
205
|
+
assert(
|
|
206
|
+
pkey.length === PRIVATE_KEY_BYTES,
|
|
207
|
+
`Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${pkey.length} bytes`,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const privateKey = toBuffer(pkey);
|
|
212
|
+
const publicKey = publicKeyCreate(privateKey, false).slice(1); // throw away leading byte
|
|
213
|
+
const messageHash = Buffer.from(
|
|
214
|
+
sha3.keccak_256.update(toBuffer(message)).digest(),
|
|
215
|
+
);
|
|
216
|
+
const {signature, recid: recoveryId} = ecdsaSign(messageHash, privateKey);
|
|
217
|
+
|
|
218
|
+
return this.createInstructionWithPublicKey({
|
|
219
|
+
publicKey,
|
|
220
|
+
message,
|
|
221
|
+
signature,
|
|
222
|
+
recoveryId,
|
|
223
|
+
instructionIndex,
|
|
224
|
+
});
|
|
225
|
+
} catch (error) {
|
|
226
|
+
throw new Error(`Error creating instruction; ${error}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|