@ar.io/sdk 4.0.0-solana.35 → 4.0.0-solana.36
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.
|
@@ -18,15 +18,18 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Produces the EXACT bytes a recipient signs to release an escrowed
|
|
20
20
|
* ANT. Output MUST be byte-identical to the Rust implementation in
|
|
21
|
-
* `
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* `ario-ant-escrow/src/canonical.rs::build_ant_escrow_claim_message`
|
|
22
|
+
* (header `ANT_ESCROW_CLAIM_HEADER = "ar.io ant-escrow claim"`). The on-chain
|
|
23
|
+
* program reconstructs these exact bytes and verifies the signature against
|
|
24
|
+
* them, so any drift (header, field set, or ordering) makes every claim fail
|
|
25
|
+
* `EthereumAddressMismatch` / signature verification.
|
|
24
26
|
*
|
|
25
27
|
* Format (UTF-8, line-feed separated, no trailing newline):
|
|
26
28
|
*
|
|
27
29
|
* ```text
|
|
28
|
-
* ar.io ant-escrow claim
|
|
30
|
+
* ar.io ant-escrow claim
|
|
29
31
|
* network: <network>
|
|
32
|
+
* recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
|
|
30
33
|
* ant: <ant_mint_base58>
|
|
31
34
|
* claimant: <claimant_solana_pubkey_base58>
|
|
32
35
|
* nonce: <nonce_hex_lowercase>
|
|
@@ -37,8 +40,9 @@
|
|
|
37
40
|
* - Ethereum: `wallet.signMessage(bytes)` → 65-byte ECDSA + EIP-191 sig
|
|
38
41
|
* (the wallet applies the EIP-191 prefix; on-chain code re-applies it).
|
|
39
42
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
44
|
+
/** Header literal — must match Rust `ANT_ESCROW_CLAIM_HEADER`. */
|
|
45
|
+
const CANONICAL_HEADER = 'ar.io ant-escrow claim';
|
|
42
46
|
/**
|
|
43
47
|
* Build the canonical claim message bytes. UTF-8 encoded, no trailing
|
|
44
48
|
* newline, exactly the format shown in the docstring.
|
|
@@ -52,21 +56,23 @@ export function canonicalMessage(input) {
|
|
|
52
56
|
}
|
|
53
57
|
const text = `${CANONICAL_HEADER}\n` +
|
|
54
58
|
`network: ${input.network}\n` +
|
|
59
|
+
`recipient: ${deriveRecipientId(input.recipient)}\n` +
|
|
55
60
|
`ant: ${input.antMint}\n` +
|
|
56
61
|
`claimant: ${input.claimant}\n` +
|
|
57
62
|
`nonce: ${bytesToHexLower(input.nonce)}`;
|
|
58
63
|
return new TextEncoder().encode(text);
|
|
59
64
|
}
|
|
60
|
-
/** Header literal — must match Rust `
|
|
61
|
-
const CANONICAL_HEADER_V2 = 'ar.io escrow claim
|
|
65
|
+
/** Header literal — must match Rust `ESCROW_CLAIM_HEADER`. */
|
|
66
|
+
const CANONICAL_HEADER_V2 = 'ar.io escrow claim';
|
|
62
67
|
/**
|
|
63
68
|
* Build the v2 canonical claim message bytes for token/vault escrows.
|
|
64
69
|
* UTF-8 encoded, no trailing newline.
|
|
65
70
|
*
|
|
66
71
|
* Format:
|
|
67
72
|
* ```text
|
|
68
|
-
* ar.io escrow claim
|
|
73
|
+
* ar.io escrow claim
|
|
69
74
|
* network: <network>
|
|
75
|
+
* recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
|
|
70
76
|
* type: <token|vault>
|
|
71
77
|
* asset: <asset_id_hex_lowercase_64chars>
|
|
72
78
|
* amount: <u64_decimal>
|
|
@@ -85,6 +91,7 @@ export function canonicalMessageV2(input) {
|
|
|
85
91
|
}
|
|
86
92
|
const text = `${CANONICAL_HEADER_V2}\n` +
|
|
87
93
|
`network: ${input.network}\n` +
|
|
94
|
+
`recipient: ${deriveRecipientId(input.recipient)}\n` +
|
|
88
95
|
`type: ${input.assetType}\n` +
|
|
89
96
|
`asset: ${bytesToHexLower(input.assetId)}\n` +
|
|
90
97
|
`amount: ${input.amount.toString()}\n` +
|
|
@@ -95,6 +102,20 @@ export function canonicalMessageV2(input) {
|
|
|
95
102
|
// =========================================
|
|
96
103
|
// Shared utilities
|
|
97
104
|
// =========================================
|
|
105
|
+
/**
|
|
106
|
+
* Recipient identity bound into the claim message — `base64url(sha256(bytes))`
|
|
107
|
+
* with no padding (32-byte hash → 43 chars). Byte-identical to the contract's
|
|
108
|
+
* `canonical.rs::derive_recipient_id_b64url`. Input is the recipient pubkey
|
|
109
|
+
* bytes the deposit targeted (ETH 20-byte address / Solana 32-byte pubkey /
|
|
110
|
+
* Arweave RSA modulus, etc.).
|
|
111
|
+
*/
|
|
112
|
+
export function deriveRecipientId(recipient) {
|
|
113
|
+
if (recipient.length === 0) {
|
|
114
|
+
throw new Error('deriveRecipientId: recipient bytes must be non-empty');
|
|
115
|
+
}
|
|
116
|
+
// Node's 'base64url' encoding is unpadded — matches the Rust no-pad alphabet.
|
|
117
|
+
return Buffer.from(sha256(recipient)).toString('base64url');
|
|
118
|
+
}
|
|
98
119
|
/** Lowercase-hex encoding. Matches Rust `encode_hex_lowercase`. */
|
|
99
120
|
export function bytesToHexLower(bytes) {
|
|
100
121
|
let s = '';
|
package/lib/esm/solana/index.js
CHANGED
|
@@ -91,7 +91,7 @@ export { ANTEscrow, TokenEscrow,
|
|
|
91
91
|
// in lock-step so users never see a raw on-chain error.
|
|
92
92
|
assertVaultClaimable, isVaultClaimable, CLOCK_SKEW_TOLERANCE_SECONDS, } from './escrow.js';
|
|
93
93
|
// Canonical claim-message helper (byte-equivalent to Rust impl)
|
|
94
|
-
export { canonicalMessage, canonicalMessageV2, bytesToHexLower, } from './canonical-message.js';
|
|
94
|
+
export { canonicalMessage, canonicalMessageV2, deriveRecipientId, bytesToHexLower, } from './canonical-message.js';
|
|
95
95
|
// ANT spawn (mint MPL Core asset + initialize ario-ant state in one tx)
|
|
96
96
|
export { spawnSolanaANT, ARIO_LOGO_TX_ID, DEFAULT_ANT_TRANSACTION_ID, } from './spawn-ant.js';
|
|
97
97
|
// PDA derivation
|
package/lib/esm/version.js
CHANGED
|
@@ -18,15 +18,18 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Produces the EXACT bytes a recipient signs to release an escrowed
|
|
20
20
|
* ANT. Output MUST be byte-identical to the Rust implementation in
|
|
21
|
-
* `
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* `ario-ant-escrow/src/canonical.rs::build_ant_escrow_claim_message`
|
|
22
|
+
* (header `ANT_ESCROW_CLAIM_HEADER = "ar.io ant-escrow claim"`). The on-chain
|
|
23
|
+
* program reconstructs these exact bytes and verifies the signature against
|
|
24
|
+
* them, so any drift (header, field set, or ordering) makes every claim fail
|
|
25
|
+
* `EthereumAddressMismatch` / signature verification.
|
|
24
26
|
*
|
|
25
27
|
* Format (UTF-8, line-feed separated, no trailing newline):
|
|
26
28
|
*
|
|
27
29
|
* ```text
|
|
28
|
-
* ar.io ant-escrow claim
|
|
30
|
+
* ar.io ant-escrow claim
|
|
29
31
|
* network: <network>
|
|
32
|
+
* recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
|
|
30
33
|
* ant: <ant_mint_base58>
|
|
31
34
|
* claimant: <claimant_solana_pubkey_base58>
|
|
32
35
|
* nonce: <nonce_hex_lowercase>
|
|
@@ -50,6 +53,12 @@ export interface CanonicalMessageInput {
|
|
|
50
53
|
/** Solana pubkey that will receive the ANT on claim. Bound into the
|
|
51
54
|
* signature so front-runners can't redirect. */
|
|
52
55
|
claimant: Address;
|
|
56
|
+
/** Recipient identity pubkey bytes the deposit targeted (ETH 20-byte
|
|
57
|
+
* address, Solana 32-byte pubkey, or Arweave RSA modulus). Bound into the
|
|
58
|
+
* message as `recipient: base64url(sha256(bytes))` to match the contract's
|
|
59
|
+
* `derive_recipient_id_b64url`. REQUIRED — the program reconstructs this
|
|
60
|
+
* line, so omitting it makes the claim mismatch. */
|
|
61
|
+
recipient: Uint8Array;
|
|
53
62
|
/** 32-byte anti-replay nonce — read from the EscrowAnt account. */
|
|
54
63
|
nonce: Uint8Array;
|
|
55
64
|
}
|
|
@@ -72,6 +81,12 @@ export interface CanonicalMessageV2Input {
|
|
|
72
81
|
amount: bigint;
|
|
73
82
|
/** Solana pubkey that will receive the tokens on claim. */
|
|
74
83
|
claimant: Address;
|
|
84
|
+
/** Recipient identity pubkey bytes the deposit targeted (ETH 20-byte
|
|
85
|
+
* address, Solana 32-byte pubkey, or Arweave RSA modulus). Bound into the
|
|
86
|
+
* message as `recipient: base64url(sha256(bytes))` to match the contract's
|
|
87
|
+
* `derive_recipient_id_b64url`. REQUIRED — the program reconstructs this
|
|
88
|
+
* line, so omitting it makes the claim mismatch. */
|
|
89
|
+
recipient: Uint8Array;
|
|
75
90
|
/** 32-byte anti-replay nonce — read from the EscrowToken account. */
|
|
76
91
|
nonce: Uint8Array;
|
|
77
92
|
}
|
|
@@ -81,8 +96,9 @@ export interface CanonicalMessageV2Input {
|
|
|
81
96
|
*
|
|
82
97
|
* Format:
|
|
83
98
|
* ```text
|
|
84
|
-
* ar.io escrow claim
|
|
99
|
+
* ar.io escrow claim
|
|
85
100
|
* network: <network>
|
|
101
|
+
* recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
|
|
86
102
|
* type: <token|vault>
|
|
87
103
|
* asset: <asset_id_hex_lowercase_64chars>
|
|
88
104
|
* amount: <u64_decimal>
|
|
@@ -93,5 +109,13 @@ export interface CanonicalMessageV2Input {
|
|
|
93
109
|
* @throws if `assetId` or `nonce` aren't exactly 32 bytes.
|
|
94
110
|
*/
|
|
95
111
|
export declare function canonicalMessageV2(input: CanonicalMessageV2Input): Uint8Array;
|
|
112
|
+
/**
|
|
113
|
+
* Recipient identity bound into the claim message — `base64url(sha256(bytes))`
|
|
114
|
+
* with no padding (32-byte hash → 43 chars). Byte-identical to the contract's
|
|
115
|
+
* `canonical.rs::derive_recipient_id_b64url`. Input is the recipient pubkey
|
|
116
|
+
* bytes the deposit targeted (ETH 20-byte address / Solana 32-byte pubkey /
|
|
117
|
+
* Arweave RSA modulus, etc.).
|
|
118
|
+
*/
|
|
119
|
+
export declare function deriveRecipientId(recipient: Uint8Array): string;
|
|
96
120
|
/** Lowercase-hex encoding. Matches Rust `encode_hex_lowercase`. */
|
|
97
121
|
export declare function bytesToHexLower(bytes: Uint8Array): string;
|
|
@@ -68,7 +68,7 @@ export type { SolanaANTRegistryWriteableConfig } from './ant-registry-writeable.
|
|
|
68
68
|
export type { AclMaintenanceOp, AclMaintenanceRole, } from '../types/ant-registry.js';
|
|
69
69
|
export { ANTEscrow, TokenEscrow, assertVaultClaimable, isVaultClaimable, CLOCK_SKEW_TOLERANCE_SECONDS, } from './escrow.js';
|
|
70
70
|
export type { ANTEscrowConfig, EscrowAntState, EscrowAssetType, EscrowProtocol, EscrowTokenState, } from './escrow.js';
|
|
71
|
-
export { canonicalMessage, canonicalMessageV2, bytesToHexLower, } from './canonical-message.js';
|
|
71
|
+
export { canonicalMessage, canonicalMessageV2, deriveRecipientId, bytesToHexLower, } from './canonical-message.js';
|
|
72
72
|
export type { CanonicalMessageInput, CanonicalMessageV2Input, EscrowNetwork, } from './canonical-message.js';
|
|
73
73
|
export { spawnSolanaANT, ARIO_LOGO_TX_ID, DEFAULT_ANT_TRANSACTION_ID, } from './spawn-ant.js';
|
|
74
74
|
export type { SpawnSolanaANTParams, SpawnSolanaANTResult, SpawnSolanaANTState, } from './spawn-ant.js';
|
package/lib/types/version.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ar.io/sdk",
|
|
3
|
-
"version": "4.0.0-solana.
|
|
3
|
+
"version": "4.0.0-solana.36",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/ar-io/ar-io-sdk.git"
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
117
|
"@ar.io/solana-contracts": "0.7.0-staging.17",
|
|
118
|
+
"@noble/hashes": "^1.8.0",
|
|
118
119
|
"@solana-program/address-lookup-table": "^0.11.0",
|
|
119
120
|
"@solana-program/compute-budget": "^0.15.0",
|
|
120
121
|
"@solana-program/token": "^0.13.0",
|