@thru/programs 0.2.22 → 0.2.24
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/dist/multicall/index.cjs +2579 -0
- package/dist/multicall/index.cjs.map +1 -0
- package/dist/multicall/index.d.cts +253 -0
- package/dist/multicall/index.d.ts +253 -0
- package/dist/multicall/index.js +2573 -0
- package/dist/multicall/index.js.map +1 -0
- package/dist/passkey-manager/index.cjs +582 -706
- package/dist/passkey-manager/index.cjs.map +1 -1
- package/dist/passkey-manager/index.d.cts +20 -14
- package/dist/passkey-manager/index.d.ts +20 -14
- package/dist/passkey-manager/index.js +551 -673
- package/dist/passkey-manager/index.js.map +1 -1
- package/package.json +7 -2
- package/src/multicall/abi/thru/common/primitives/types.ts +2265 -0
- package/src/multicall/abi/thru/program/multicall/types.ts +1232 -0
- package/src/multicall/index.test.ts +46 -0
- package/src/multicall/index.ts +81 -0
- package/src/passkey-manager/abi/thru/blockchain/state_proof/types.ts +95 -19
- package/src/passkey-manager/abi/thru/common/primitives/types.ts +111 -37
- package/src/passkey-manager/abi/thru/program/passkey_manager/types.ts +248 -660
- package/src/passkey-manager/challenge.ts +52 -12
- package/src/passkey-manager/constants.ts +0 -1
- package/src/passkey-manager/index.ts +4 -4
- package/src/passkey-manager/instructions/add-authority.ts +8 -2
- package/src/passkey-manager/instructions/remove-authority.ts +9 -2
- package/src/passkey-manager/instructions/validate.ts +60 -14
- package/src/passkey-manager/target-instruction.ts +29 -0
- package/src/passkey-manager/types.ts +16 -0
- package/src/passkey-manager/validate.test.ts +173 -0
- package/tsup.config.ts +1 -0
- package/src/passkey-manager/instructions/invoke.ts +0 -25
- package/src/passkey-manager/instructions/shared.ts +0 -12
|
@@ -1,38 +1,78 @@
|
|
|
1
|
+
import type { TargetInstructionParams } from './types';
|
|
2
|
+
import { buildTargetInstructionBytes } from './target-instruction';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Create challenge for VALIDATE instruction.
|
|
3
|
-
* SHA256(nonce ||
|
|
6
|
+
* SHA256(domain || nonce || wallet_account_idx || auth_idx || account_count ||
|
|
7
|
+
* account_0 || account_1 || ... || target_instruction)
|
|
4
8
|
*/
|
|
9
|
+
export const VALIDATE_CHALLENGE_DOMAIN = 'thru.passkey.validate';
|
|
10
|
+
|
|
11
|
+
function writeU64LE(target: Uint8Array, offset: number, value: bigint): void {
|
|
12
|
+
let remaining = value;
|
|
13
|
+
for (let i = 0; i < 8; i++) {
|
|
14
|
+
target[offset + i] = Number(remaining & 0xffn);
|
|
15
|
+
remaining >>= 8n;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
export async function createValidateChallenge(
|
|
6
20
|
nonce: bigint,
|
|
7
21
|
accountAddresses: string[],
|
|
8
|
-
|
|
22
|
+
walletAccountIdx: number,
|
|
23
|
+
authIdx: number,
|
|
24
|
+
targetInstruction: TargetInstructionParams
|
|
9
25
|
): Promise<Uint8Array> {
|
|
26
|
+
const targetInstructionBytes = buildTargetInstructionBytes(targetInstruction);
|
|
10
27
|
const encoder = new TextEncoder();
|
|
28
|
+
const domainBytes = encoder.encode(VALIDATE_CHALLENGE_DOMAIN);
|
|
11
29
|
const accountBytes = accountAddresses.map((address) => {
|
|
12
|
-
|
|
30
|
+
const bytes = encoder.encode(address);
|
|
31
|
+
if (bytes.length !== 46) {
|
|
32
|
+
throw new Error('accountAddresses must contain ta addresses');
|
|
33
|
+
}
|
|
34
|
+
return bytes;
|
|
13
35
|
});
|
|
36
|
+
if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
|
|
37
|
+
throw new Error('walletAccountIdx must be 0-65535');
|
|
38
|
+
}
|
|
39
|
+
if (authIdx < 0 || authIdx > 0xff) throw new Error('authIdx must be 0-255');
|
|
40
|
+
if (accountBytes.length > 0xffff) throw new Error('accountAddresses length must be 0-65535');
|
|
14
41
|
|
|
15
42
|
const totalSize =
|
|
16
|
-
|
|
17
|
-
|
|
43
|
+
domainBytes.length +
|
|
44
|
+
8 +
|
|
45
|
+
2 +
|
|
46
|
+
1 +
|
|
47
|
+
2 +
|
|
48
|
+
accountBytes.reduce((sum, bytes) => sum + bytes.length, 0) +
|
|
49
|
+
targetInstructionBytes.length;
|
|
18
50
|
const challengeData = new Uint8Array(totalSize);
|
|
19
51
|
|
|
20
52
|
let offset = 0;
|
|
53
|
+
challengeData.set(domainBytes, offset);
|
|
54
|
+
offset += domainBytes.length;
|
|
21
55
|
|
|
22
|
-
|
|
23
|
-
let v = nonce;
|
|
24
|
-
for (let i = 0; i < 8; i++) {
|
|
25
|
-
challengeData[offset + i] = Number(v & 0xffn);
|
|
26
|
-
v >>= 8n;
|
|
27
|
-
}
|
|
56
|
+
writeU64LE(challengeData, offset, nonce);
|
|
28
57
|
offset += 8;
|
|
29
58
|
|
|
59
|
+
challengeData[offset] = walletAccountIdx & 0xff;
|
|
60
|
+
challengeData[offset + 1] = (walletAccountIdx >> 8) & 0xff;
|
|
61
|
+
offset += 2;
|
|
62
|
+
|
|
63
|
+
challengeData[offset] = authIdx & 0xff;
|
|
64
|
+
offset += 1;
|
|
65
|
+
|
|
66
|
+
challengeData[offset] = accountBytes.length & 0xff;
|
|
67
|
+
challengeData[offset + 1] = (accountBytes.length >> 8) & 0xff;
|
|
68
|
+
offset += 2;
|
|
69
|
+
|
|
30
70
|
for (const bytes of accountBytes) {
|
|
31
71
|
challengeData.set(bytes, offset);
|
|
32
72
|
offset += bytes.length;
|
|
33
73
|
}
|
|
34
74
|
|
|
35
|
-
challengeData.set(
|
|
75
|
+
challengeData.set(targetInstructionBytes, offset);
|
|
36
76
|
|
|
37
77
|
const hashBuffer = await crypto.subtle.digest('SHA-256', challengeData);
|
|
38
78
|
return new Uint8Array(hashBuffer);
|
|
@@ -5,7 +5,6 @@ export const PASSKEY_MANAGER_PROGRAM_ADDRESS =
|
|
|
5
5
|
export const INSTRUCTION_CREATE = 0x00;
|
|
6
6
|
export const INSTRUCTION_VALIDATE = 0x01;
|
|
7
7
|
export const INSTRUCTION_TRANSFER = 0x02;
|
|
8
|
-
export const INSTRUCTION_INVOKE = 0x03;
|
|
9
8
|
export const INSTRUCTION_ADD_AUTHORITY = 0x04;
|
|
10
9
|
export const INSTRUCTION_REMOVE_AUTHORITY = 0x05;
|
|
11
10
|
export const INSTRUCTION_REGISTER_CREDENTIAL = 0x06;
|
|
@@ -4,7 +4,6 @@ export {
|
|
|
4
4
|
INSTRUCTION_CREATE,
|
|
5
5
|
INSTRUCTION_VALIDATE,
|
|
6
6
|
INSTRUCTION_TRANSFER,
|
|
7
|
-
INSTRUCTION_INVOKE,
|
|
8
7
|
INSTRUCTION_ADD_AUTHORITY,
|
|
9
8
|
INSTRUCTION_REMOVE_AUTHORITY,
|
|
10
9
|
INSTRUCTION_REGISTER_CREDENTIAL,
|
|
@@ -17,7 +16,10 @@ export type {
|
|
|
17
16
|
Authority,
|
|
18
17
|
CreateInstructionParams,
|
|
19
18
|
TransferInstructionParams,
|
|
19
|
+
TargetInstructionParams,
|
|
20
20
|
ValidateInstructionParams,
|
|
21
|
+
AddAuthorityInstructionParams,
|
|
22
|
+
RemoveAuthorityInstructionParams,
|
|
21
23
|
RegisterCredentialInstructionParams,
|
|
22
24
|
AccountContext,
|
|
23
25
|
WalletSigner,
|
|
@@ -32,14 +34,12 @@ export type {
|
|
|
32
34
|
export { encodeCreateInstruction } from './instructions/create';
|
|
33
35
|
export { encodeValidateInstruction } from './instructions/validate';
|
|
34
36
|
export { encodeTransferInstruction } from './instructions/transfer';
|
|
35
|
-
export { encodeInvokeInstruction } from './instructions/invoke';
|
|
36
37
|
export { encodeAddAuthorityInstruction } from './instructions/add-authority';
|
|
37
38
|
export { encodeRemoveAuthorityInstruction } from './instructions/remove-authority';
|
|
38
39
|
export { encodeRegisterCredentialInstruction } from './instructions/register-credential';
|
|
39
|
-
export { concatenateInstructions } from './instructions/shared';
|
|
40
40
|
|
|
41
41
|
// Challenge
|
|
42
|
-
export { createValidateChallenge } from './challenge';
|
|
42
|
+
export { createValidateChallenge, VALIDATE_CHALLENGE_DOMAIN } from './challenge';
|
|
43
43
|
|
|
44
44
|
// Seeds & derivation
|
|
45
45
|
export { createWalletSeed, deriveWalletAddress, createCredentialLookupSeed, deriveCredentialLookupAddress } from './seeds';
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AddAuthorityInstructionParams } from '../types';
|
|
2
2
|
import {
|
|
3
3
|
AddAuthorityArgsBuilder,
|
|
4
4
|
PasskeyInstructionBuilder,
|
|
5
5
|
} from '../abi/thru/program/passkey_manager/types';
|
|
6
6
|
import { buildAuthority } from './create';
|
|
7
7
|
|
|
8
|
-
export function encodeAddAuthorityInstruction(params:
|
|
8
|
+
export function encodeAddAuthorityInstruction(params: AddAuthorityInstructionParams): Uint8Array {
|
|
9
|
+
const { walletAccountIdx } = params;
|
|
10
|
+
if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
|
|
11
|
+
throw new Error('walletAccountIdx must be 0-65535');
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
const authorityBytes = buildAuthority(params.authority);
|
|
10
15
|
|
|
11
16
|
const argsPayload = new AddAuthorityArgsBuilder()
|
|
17
|
+
.set_wallet_account_idx(walletAccountIdx)
|
|
12
18
|
.set_authority(authorityBytes)
|
|
13
19
|
.build();
|
|
14
20
|
|
|
@@ -2,12 +2,19 @@ import {
|
|
|
2
2
|
RemoveAuthorityArgsBuilder,
|
|
3
3
|
PasskeyInstructionBuilder,
|
|
4
4
|
} from '../abi/thru/program/passkey_manager/types';
|
|
5
|
+
import type { RemoveAuthorityInstructionParams } from '../types';
|
|
5
6
|
|
|
6
|
-
export function encodeRemoveAuthorityInstruction(
|
|
7
|
-
|
|
7
|
+
export function encodeRemoveAuthorityInstruction(
|
|
8
|
+
params: RemoveAuthorityInstructionParams
|
|
9
|
+
): Uint8Array {
|
|
10
|
+
const { walletAccountIdx, authIdx } = params;
|
|
11
|
+
if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
|
|
12
|
+
throw new Error('walletAccountIdx must be 0-65535');
|
|
13
|
+
}
|
|
8
14
|
if (authIdx < 0 || authIdx > 0xff) throw new Error('authIdx must be 0-255');
|
|
9
15
|
|
|
10
16
|
const argsPayload = new RemoveAuthorityArgsBuilder()
|
|
17
|
+
.set_wallet_account_idx(walletAccountIdx)
|
|
11
18
|
.set_auth_idx(authIdx)
|
|
12
19
|
.build();
|
|
13
20
|
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
import type { ValidateInstructionParams } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { PasskeyInstructionBuilder } from '../abi/thru/program/passkey_manager/types';
|
|
3
|
+
import { buildTargetInstructionBytes } from '../target-instruction';
|
|
4
|
+
|
|
5
|
+
const U8_SIZE = Uint8Array.BYTES_PER_ELEMENT;
|
|
6
|
+
const U16_SIZE = Uint16Array.BYTES_PER_ELEMENT;
|
|
7
|
+
const P256_COORDINATE_SIZE = 32;
|
|
8
|
+
const VALIDATE_FIXED_PREFIX_SIZE =
|
|
9
|
+
U16_SIZE +
|
|
10
|
+
U8_SIZE +
|
|
11
|
+
P256_COORDINATE_SIZE +
|
|
12
|
+
P256_COORDINATE_SIZE +
|
|
13
|
+
U16_SIZE +
|
|
14
|
+
U16_SIZE;
|
|
15
|
+
|
|
16
|
+
function writeU16LE(target: Uint8Array, offset: number, value: number): void {
|
|
17
|
+
target[offset] = value & 0xff;
|
|
18
|
+
target[offset + 1] = (value >> 8) & 0xff;
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
export function encodeValidateInstruction(params: ValidateInstructionParams): Uint8Array {
|
|
8
|
-
const {
|
|
9
|
-
|
|
22
|
+
const {
|
|
23
|
+
walletAccountIdx,
|
|
24
|
+
authIdx,
|
|
25
|
+
targetInstruction,
|
|
26
|
+
signatureR,
|
|
27
|
+
signatureS,
|
|
28
|
+
authenticatorData,
|
|
29
|
+
clientDataJSON,
|
|
30
|
+
} = params;
|
|
10
31
|
|
|
11
32
|
if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
|
|
12
33
|
throw new Error('walletAccountIdx must be 0-65535');
|
|
@@ -14,15 +35,40 @@ export function encodeValidateInstruction(params: ValidateInstructionParams): Ui
|
|
|
14
35
|
if (authIdx < 0 || authIdx > 0xff) throw new Error('authIdx must be 0-255');
|
|
15
36
|
if (signatureR.length !== 32) throw new Error('signatureR must be 32 bytes');
|
|
16
37
|
if (signatureS.length !== 32) throw new Error('signatureS must be 32 bytes');
|
|
38
|
+
if (authenticatorData.length > 0xffff) {
|
|
39
|
+
throw new Error('authenticatorData length must be 0-65535');
|
|
40
|
+
}
|
|
41
|
+
if (clientDataJSON.length > 0xffff) {
|
|
42
|
+
throw new Error('clientDataJSON length must be 0-65535');
|
|
43
|
+
}
|
|
17
44
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
45
|
+
const targetInstructionBytes = buildTargetInstructionBytes(targetInstruction);
|
|
46
|
+
|
|
47
|
+
const argsPayload = new Uint8Array(
|
|
48
|
+
VALIDATE_FIXED_PREFIX_SIZE +
|
|
49
|
+
authenticatorData.length +
|
|
50
|
+
clientDataJSON.length +
|
|
51
|
+
targetInstructionBytes.length
|
|
52
|
+
);
|
|
53
|
+
let offset = 0;
|
|
54
|
+
|
|
55
|
+
writeU16LE(argsPayload, offset, walletAccountIdx);
|
|
56
|
+
offset += 2;
|
|
57
|
+
argsPayload[offset] = authIdx;
|
|
58
|
+
offset += 1;
|
|
59
|
+
argsPayload.set(signatureR, offset);
|
|
60
|
+
offset += signatureR.length;
|
|
61
|
+
argsPayload.set(signatureS, offset);
|
|
62
|
+
offset += signatureS.length;
|
|
63
|
+
writeU16LE(argsPayload, offset, authenticatorData.length);
|
|
64
|
+
offset += 2;
|
|
65
|
+
writeU16LE(argsPayload, offset, clientDataJSON.length);
|
|
66
|
+
offset += 2;
|
|
67
|
+
argsPayload.set(authenticatorData, offset);
|
|
68
|
+
offset += authenticatorData.length;
|
|
69
|
+
argsPayload.set(clientDataJSON, offset);
|
|
70
|
+
offset += clientDataJSON.length;
|
|
71
|
+
argsPayload.set(targetInstructionBytes, offset);
|
|
26
72
|
|
|
27
73
|
return new PasskeyInstructionBuilder()
|
|
28
74
|
.payload()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InstructionData,
|
|
3
|
+
InstructionDataBuilder,
|
|
4
|
+
} from './abi/thru/common/primitives/types';
|
|
5
|
+
import type { TargetInstructionParams } from './types';
|
|
6
|
+
|
|
7
|
+
export function buildTargetInstructionBytes({
|
|
8
|
+
programIdx,
|
|
9
|
+
instructionData,
|
|
10
|
+
}: TargetInstructionParams): Uint8Array {
|
|
11
|
+
if (!Number.isInteger(programIdx) || programIdx < 0 || programIdx > 0xffff) {
|
|
12
|
+
throw new Error('programIdx must be 0-65535');
|
|
13
|
+
}
|
|
14
|
+
if (!(instructionData instanceof Uint8Array)) {
|
|
15
|
+
throw new Error('instructionData must be a Uint8Array');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const builder = new InstructionDataBuilder();
|
|
19
|
+
builder.set_program_idx(programIdx);
|
|
20
|
+
builder.data().write(instructionData).finish();
|
|
21
|
+
|
|
22
|
+
const buffer = builder.build();
|
|
23
|
+
const view = InstructionData.from_array(buffer);
|
|
24
|
+
if (!view) {
|
|
25
|
+
throw new Error('generated InstructionData failed validation');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return buffer;
|
|
29
|
+
}
|
|
@@ -77,15 +77,31 @@ export interface TransferInstructionParams {
|
|
|
77
77
|
amount: bigint;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
export interface TargetInstructionParams {
|
|
81
|
+
programIdx: number;
|
|
82
|
+
instructionData: Uint8Array;
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
export interface ValidateInstructionParams {
|
|
81
86
|
walletAccountIdx: number;
|
|
82
87
|
authIdx: number;
|
|
88
|
+
targetInstruction: TargetInstructionParams;
|
|
83
89
|
signatureR: Uint8Array;
|
|
84
90
|
signatureS: Uint8Array;
|
|
85
91
|
authenticatorData: Uint8Array;
|
|
86
92
|
clientDataJSON: Uint8Array;
|
|
87
93
|
}
|
|
88
94
|
|
|
95
|
+
export interface AddAuthorityInstructionParams {
|
|
96
|
+
walletAccountIdx: number;
|
|
97
|
+
authority: Authority;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface RemoveAuthorityInstructionParams {
|
|
101
|
+
walletAccountIdx: number;
|
|
102
|
+
authIdx: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
export interface AccountContext {
|
|
90
106
|
readWriteAddresses: string[];
|
|
91
107
|
readOnlyAddresses: string[];
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { encodeAddress } from '@thru/sdk/helpers';
|
|
4
|
+
import { createValidateChallenge } from './challenge';
|
|
5
|
+
import { encodeAddAuthorityInstruction } from './instructions/add-authority';
|
|
6
|
+
import { encodeRemoveAuthorityInstruction } from './instructions/remove-authority';
|
|
7
|
+
import { encodeValidateInstruction } from './instructions/validate';
|
|
8
|
+
import {
|
|
9
|
+
MULTICALL_PROGRAM_ADDRESS,
|
|
10
|
+
MULTICALL_PROGRAM_PUBKEY,
|
|
11
|
+
buildMulticallInstruction,
|
|
12
|
+
} from '../multicall';
|
|
13
|
+
import {
|
|
14
|
+
InstructionData,
|
|
15
|
+
InstructionDataBuilder,
|
|
16
|
+
} from './abi/thru/common/primitives/types';
|
|
17
|
+
|
|
18
|
+
function bytes(value: number, len: number): Uint8Array {
|
|
19
|
+
return new Uint8Array(len).fill(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function u16le(value: number): Uint8Array {
|
|
23
|
+
return new Uint8Array([value & 0xff, (value >> 8) & 0xff]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function u64le(value: bigint): Uint8Array {
|
|
27
|
+
const out = new Uint8Array(8);
|
|
28
|
+
let v = value;
|
|
29
|
+
for (let i = 0; i < 8; i++) {
|
|
30
|
+
out[i] = Number(v & 0xffn);
|
|
31
|
+
v >>= 8n;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function concat(parts: Uint8Array[]): Uint8Array {
|
|
37
|
+
const out = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
|
|
38
|
+
let offset = 0;
|
|
39
|
+
for (const part of parts) {
|
|
40
|
+
out.set(part, offset);
|
|
41
|
+
offset += part.length;
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildInstructionDataFixture(
|
|
47
|
+
programIdx: number,
|
|
48
|
+
instructionData: Uint8Array
|
|
49
|
+
): Uint8Array {
|
|
50
|
+
const builder = new InstructionDataBuilder();
|
|
51
|
+
builder.set_program_idx(programIdx);
|
|
52
|
+
builder.data().write(instructionData).finish();
|
|
53
|
+
return builder.build();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe('passkey manager validate helpers', () => {
|
|
57
|
+
it('creates the validate challenge preimage', async () => {
|
|
58
|
+
const accountAddresses = [
|
|
59
|
+
encodeAddress(bytes(0x01, 32)),
|
|
60
|
+
encodeAddress(bytes(0x02, 32)),
|
|
61
|
+
encodeAddress(bytes(0x03, 32)),
|
|
62
|
+
];
|
|
63
|
+
const programIdx = 9;
|
|
64
|
+
const instructionData = new Uint8Array([0xaa, 0xbb, 0xcc]);
|
|
65
|
+
const targetInstructionBytes = buildInstructionDataFixture(programIdx, instructionData);
|
|
66
|
+
const text = new TextEncoder();
|
|
67
|
+
|
|
68
|
+
const expectedPreimage = concat([
|
|
69
|
+
text.encode('thru.passkey.validate'),
|
|
70
|
+
u64le(9n),
|
|
71
|
+
u16le(4),
|
|
72
|
+
new Uint8Array([2]),
|
|
73
|
+
u16le(accountAddresses.length),
|
|
74
|
+
...accountAddresses.map((address) => text.encode(address)),
|
|
75
|
+
targetInstructionBytes,
|
|
76
|
+
]);
|
|
77
|
+
const expected = new Uint8Array(
|
|
78
|
+
createHash('sha256').update(expectedPreimage).digest()
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
await expect(
|
|
82
|
+
createValidateChallenge(
|
|
83
|
+
9n,
|
|
84
|
+
accountAddresses,
|
|
85
|
+
4,
|
|
86
|
+
2,
|
|
87
|
+
{
|
|
88
|
+
programIdx,
|
|
89
|
+
instructionData,
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
).resolves.toEqual(expected);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('encodes VALIDATE with a well-known InstructionData target', () => {
|
|
96
|
+
const programIdx = 0x0706;
|
|
97
|
+
const instructionData = new Uint8Array([0xaa, 0xbb]);
|
|
98
|
+
const authenticatorData = new Uint8Array([0xcc]);
|
|
99
|
+
const clientDataJSON = new Uint8Array([0xdd, 0xee]);
|
|
100
|
+
|
|
101
|
+
const encoded = encodeValidateInstruction({
|
|
102
|
+
walletAccountIdx: 0x1234,
|
|
103
|
+
authIdx: 5,
|
|
104
|
+
targetInstruction: {
|
|
105
|
+
programIdx,
|
|
106
|
+
instructionData,
|
|
107
|
+
},
|
|
108
|
+
signatureR: bytes(0x11, 32),
|
|
109
|
+
signatureS: bytes(0x22, 32),
|
|
110
|
+
authenticatorData,
|
|
111
|
+
clientDataJSON,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(encoded[0]).toBe(0x01);
|
|
115
|
+
expect(encoded.slice(1, 3)).toEqual(u16le(0x1234));
|
|
116
|
+
expect(encoded[3]).toBe(5);
|
|
117
|
+
expect(encoded.slice(4, 36)).toEqual(bytes(0x11, 32));
|
|
118
|
+
expect(encoded.slice(36, 68)).toEqual(bytes(0x22, 32));
|
|
119
|
+
expect(encoded.slice(68, 70)).toEqual(u16le(authenticatorData.length));
|
|
120
|
+
expect(encoded.slice(70, 72)).toEqual(u16le(clientDataJSON.length));
|
|
121
|
+
expect(encoded.slice(72, 73)).toEqual(authenticatorData);
|
|
122
|
+
expect(encoded.slice(73, 75)).toEqual(clientDataJSON);
|
|
123
|
+
const targetInstructionBytes = encoded.slice(75);
|
|
124
|
+
expect(targetInstructionBytes).toEqual(
|
|
125
|
+
buildInstructionDataFixture(programIdx, instructionData)
|
|
126
|
+
);
|
|
127
|
+
const targetInstructionView = InstructionData.from_array(targetInstructionBytes);
|
|
128
|
+
expect(targetInstructionView?.get_program_idx()).toBe(programIdx);
|
|
129
|
+
expect(targetInstructionView?.get_data()).toEqual(Array.from(instructionData));
|
|
130
|
+
expect(encoded.length).toBe(87);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('encodes wallet indexes in add/remove authority instructions', () => {
|
|
134
|
+
const add = encodeAddAuthorityInstruction({
|
|
135
|
+
walletAccountIdx: 0x1234,
|
|
136
|
+
authority: {
|
|
137
|
+
tag: 1,
|
|
138
|
+
pubkeyX: bytes(0x01, 32),
|
|
139
|
+
pubkeyY: bytes(0x02, 32),
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
expect(add[0]).toBe(0x04);
|
|
143
|
+
expect(add.slice(1, 3)).toEqual(u16le(0x1234));
|
|
144
|
+
expect(add[3]).toBe(1);
|
|
145
|
+
expect(add.length).toBe(68);
|
|
146
|
+
|
|
147
|
+
const remove = encodeRemoveAuthorityInstruction({
|
|
148
|
+
walletAccountIdx: 0x1234,
|
|
149
|
+
authIdx: 9,
|
|
150
|
+
});
|
|
151
|
+
expect(remove).toEqual(new Uint8Array([0x05, 0x34, 0x12, 0x09]));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('encodes multicall instructions with the known program address', () => {
|
|
155
|
+
expect(MULTICALL_PROGRAM_ADDRESS).toBe(
|
|
156
|
+
'taAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkJ'
|
|
157
|
+
);
|
|
158
|
+
expect(MULTICALL_PROGRAM_PUBKEY[31]).toBe(9);
|
|
159
|
+
|
|
160
|
+
const encoded = buildMulticallInstruction([
|
|
161
|
+
{ programIdx: 2, instructionData: new Uint8Array([0xaa]) },
|
|
162
|
+
{ programIdx: 5, instructionData: new Uint8Array([0xbb, 0xcc]) },
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
expect(encoded).toEqual(
|
|
166
|
+
new Uint8Array([
|
|
167
|
+
0x02, 0x00,
|
|
168
|
+
0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
|
|
169
|
+
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xcc,
|
|
170
|
+
])
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
});
|
package/tsup.config.ts
CHANGED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InvokeArgsBuilder,
|
|
3
|
-
PasskeyInstructionBuilder,
|
|
4
|
-
} from '../abi/thru/program/passkey_manager/types';
|
|
5
|
-
|
|
6
|
-
export function encodeInvokeInstruction(
|
|
7
|
-
programPubkey: Uint8Array,
|
|
8
|
-
instruction: Uint8Array
|
|
9
|
-
): Uint8Array {
|
|
10
|
-
if (programPubkey.length !== 32) {
|
|
11
|
-
throw new Error('Program pubkey must be 32 bytes');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const argsPayload = new InvokeArgsBuilder()
|
|
15
|
-
.set_program_pubkey(programPubkey)
|
|
16
|
-
.instr().write(instruction).finish()
|
|
17
|
-
.build();
|
|
18
|
-
|
|
19
|
-
return new PasskeyInstructionBuilder()
|
|
20
|
-
.payload()
|
|
21
|
-
.select('invoke')
|
|
22
|
-
.writePayload(argsPayload)
|
|
23
|
-
.finish()
|
|
24
|
-
.build();
|
|
25
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export function concatenateInstructions(instructions: Uint8Array[]): Uint8Array {
|
|
2
|
-
const totalLength = instructions.reduce((sum, instr) => sum + instr.length, 0);
|
|
3
|
-
const result = new Uint8Array(totalLength);
|
|
4
|
-
|
|
5
|
-
let offset = 0;
|
|
6
|
-
for (const instr of instructions) {
|
|
7
|
-
result.set(instr, offset);
|
|
8
|
-
offset += instr.length;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return result;
|
|
12
|
-
}
|