@defuse-protocol/intents-sdk 0.64.0 → 0.64.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.
@@ -1,4 +1,5 @@
1
1
  const require_rolldown_runtime = require('../../../_virtual/rolldown_runtime.cjs');
2
+ const require_ton_address = require('../../lib/ton-address.cjs');
2
3
  let _noble_hashes_sha2 = require("@noble/hashes/sha2");
3
4
 
4
5
  //#region src/intents/intent-hashes/ton-connect.ts
@@ -13,27 +14,10 @@ function numberToBigEndian(num, bytes) {
13
14
  }
14
15
  return result;
15
16
  }
16
- /**
17
- * Parse TON address string to TonAddress object
18
- * Supports raw format: "workchain:address_hex"
19
- * Example: "0:f4809e5ffac9dc42a6b1d94c5e74ad5fd86378de675c805f2274d0055cbc9378"
20
- *
21
- * @param addressString - TON address string in raw format
22
- * @returns Parsed TonAddress object
23
- */
24
17
  function parseTonAddress(addressString) {
25
- const parts = addressString.split(":");
26
- if (parts.length !== 2) throw new Error(`Invalid TON address format: ${addressString}. Expected "workchain:address_hex"`);
27
- const workchainId = parseInt(parts[0], 10);
28
- if (Number.isNaN(workchainId)) throw new Error(`Invalid workchain ID: ${parts[0]}`);
29
- const addressHex = parts[1].startsWith("0x") ? parts[1].slice(2) : parts[1];
30
- if (addressHex.length !== 64) throw new Error(`Invalid address length: expected 64 hex characters, got ${addressHex.length}`);
31
- const address = new Uint8Array(32);
32
- for (let i = 0; i < 32; i++) address[i] = parseInt(addressHex.slice(i * 2, i * 2 + 2), 16);
33
- return {
34
- workchainId,
35
- address
36
- };
18
+ const parsed = require_ton_address.tryParseTonAddress(addressString);
19
+ if (parsed === null) throw new Error(`Invalid TON address: ${addressString}`);
20
+ return parsed;
37
21
  }
38
22
  /**
39
23
  * Compute the SHA-256 hash of a TON Connect payload
@@ -1,3 +1,4 @@
1
+ import { tryParseTonAddress } from "../../lib/ton-address.js";
1
2
  import { sha256 } from "@noble/hashes/sha2";
2
3
 
3
4
  //#region src/intents/intent-hashes/ton-connect.ts
@@ -12,27 +13,10 @@ function numberToBigEndian(num, bytes) {
12
13
  }
13
14
  return result;
14
15
  }
15
- /**
16
- * Parse TON address string to TonAddress object
17
- * Supports raw format: "workchain:address_hex"
18
- * Example: "0:f4809e5ffac9dc42a6b1d94c5e74ad5fd86378de675c805f2274d0055cbc9378"
19
- *
20
- * @param addressString - TON address string in raw format
21
- * @returns Parsed TonAddress object
22
- */
23
16
  function parseTonAddress(addressString) {
24
- const parts = addressString.split(":");
25
- if (parts.length !== 2) throw new Error(`Invalid TON address format: ${addressString}. Expected "workchain:address_hex"`);
26
- const workchainId = parseInt(parts[0], 10);
27
- if (Number.isNaN(workchainId)) throw new Error(`Invalid workchain ID: ${parts[0]}`);
28
- const addressHex = parts[1].startsWith("0x") ? parts[1].slice(2) : parts[1];
29
- if (addressHex.length !== 64) throw new Error(`Invalid address length: expected 64 hex characters, got ${addressHex.length}`);
30
- const address = new Uint8Array(32);
31
- for (let i = 0; i < 32; i++) address[i] = parseInt(addressHex.slice(i * 2, i * 2 + 2), 16);
32
- return {
33
- workchainId,
34
- address
35
- };
17
+ const parsed = tryParseTonAddress(addressString);
18
+ if (parsed === null) throw new Error(`Invalid TON address: ${addressString}`);
19
+ return parsed;
36
20
  }
37
21
  /**
38
22
  * Compute the SHA-256 hash of a TON Connect payload
@@ -0,0 +1,74 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let _scure_base = require("@scure/base");
3
+
4
+ //#region src/lib/ton-address.ts
5
+ /**
6
+ * Tag byte for user-friendly TON addresses. Bit 7 sets testnet, bit 6 sets
7
+ * non-bounceable. See https://docs.ton.org/learn/overviews/addresses#user-friendly-address
8
+ */
9
+ const TON_ADDRESS_TAG_BOUNCEABLE_MAINNET = 17;
10
+ const TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET = 81;
11
+ /**
12
+ * Real TON only uses these two workchains. Other values parse fine but no
13
+ * wallet emits them, so the validator treats them as typos.
14
+ */
15
+ const TON_WORKCHAIN_BASECHAIN = 0;
16
+ const TON_WORKCHAIN_MASTERCHAIN = -1;
17
+ const TON_USER_FRIENDLY_LENGTH = 36;
18
+ function crc16ccitt(data) {
19
+ let crc = 0;
20
+ for (const byte of data) {
21
+ crc ^= byte << 8;
22
+ for (let i = 0; i < 8; i++) crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
23
+ crc &= 65535;
24
+ }
25
+ return [crc >> 8 & 255, crc & 255];
26
+ }
27
+ function parseTonUserFriendlyAddress(s) {
28
+ const normalized = s.replace(/\+/g, "-").replace(/\//g, "_");
29
+ let data;
30
+ try {
31
+ data = _scure_base.base64urlnopad.decode(normalized);
32
+ } catch {
33
+ return null;
34
+ }
35
+ if (data.length !== TON_USER_FRIENDLY_LENGTH) return null;
36
+ const [hi, lo] = crc16ccitt(data.subarray(0, 34));
37
+ if (data[34] !== hi || data[35] !== lo) return null;
38
+ const tag = data[0];
39
+ const wcByte = data[1];
40
+ return {
41
+ tag,
42
+ workchainId: wcByte > 127 ? wcByte - 256 : wcByte,
43
+ address: data.slice(2, 34)
44
+ };
45
+ }
46
+ const RAW_HEX_LENGTH = 64;
47
+ function parseTonRawAddress(s) {
48
+ const parts = s.split(":");
49
+ if (parts.length !== 2) return null;
50
+ const workchainId = parseInt(parts[0], 10);
51
+ if (Number.isNaN(workchainId)) return null;
52
+ let hex = parts[1];
53
+ if (hex.startsWith("0x")) hex = hex.slice(2);
54
+ if (hex.length !== RAW_HEX_LENGTH) return null;
55
+ if (!/^[0-9a-fA-F]+$/.test(hex)) return null;
56
+ const address = new Uint8Array(32);
57
+ for (let i = 0; i < 32; i++) address[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
58
+ return {
59
+ workchainId,
60
+ address,
61
+ tag: null
62
+ };
63
+ }
64
+ function tryParseTonAddress(s) {
65
+ if (s.includes(":")) return parseTonRawAddress(s);
66
+ return parseTonUserFriendlyAddress(s);
67
+ }
68
+
69
+ //#endregion
70
+ exports.TON_ADDRESS_TAG_BOUNCEABLE_MAINNET = TON_ADDRESS_TAG_BOUNCEABLE_MAINNET;
71
+ exports.TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET = TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET;
72
+ exports.TON_WORKCHAIN_BASECHAIN = TON_WORKCHAIN_BASECHAIN;
73
+ exports.TON_WORKCHAIN_MASTERCHAIN = TON_WORKCHAIN_MASTERCHAIN;
74
+ exports.tryParseTonAddress = tryParseTonAddress;
@@ -0,0 +1,69 @@
1
+ import { base64urlnopad } from "@scure/base";
2
+
3
+ //#region src/lib/ton-address.ts
4
+ /**
5
+ * Tag byte for user-friendly TON addresses. Bit 7 sets testnet, bit 6 sets
6
+ * non-bounceable. See https://docs.ton.org/learn/overviews/addresses#user-friendly-address
7
+ */
8
+ const TON_ADDRESS_TAG_BOUNCEABLE_MAINNET = 17;
9
+ const TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET = 81;
10
+ /**
11
+ * Real TON only uses these two workchains. Other values parse fine but no
12
+ * wallet emits them, so the validator treats them as typos.
13
+ */
14
+ const TON_WORKCHAIN_BASECHAIN = 0;
15
+ const TON_WORKCHAIN_MASTERCHAIN = -1;
16
+ const TON_USER_FRIENDLY_LENGTH = 36;
17
+ function crc16ccitt(data) {
18
+ let crc = 0;
19
+ for (const byte of data) {
20
+ crc ^= byte << 8;
21
+ for (let i = 0; i < 8; i++) crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
22
+ crc &= 65535;
23
+ }
24
+ return [crc >> 8 & 255, crc & 255];
25
+ }
26
+ function parseTonUserFriendlyAddress(s) {
27
+ const normalized = s.replace(/\+/g, "-").replace(/\//g, "_");
28
+ let data;
29
+ try {
30
+ data = base64urlnopad.decode(normalized);
31
+ } catch {
32
+ return null;
33
+ }
34
+ if (data.length !== TON_USER_FRIENDLY_LENGTH) return null;
35
+ const [hi, lo] = crc16ccitt(data.subarray(0, 34));
36
+ if (data[34] !== hi || data[35] !== lo) return null;
37
+ const tag = data[0];
38
+ const wcByte = data[1];
39
+ return {
40
+ tag,
41
+ workchainId: wcByte > 127 ? wcByte - 256 : wcByte,
42
+ address: data.slice(2, 34)
43
+ };
44
+ }
45
+ const RAW_HEX_LENGTH = 64;
46
+ function parseTonRawAddress(s) {
47
+ const parts = s.split(":");
48
+ if (parts.length !== 2) return null;
49
+ const workchainId = parseInt(parts[0], 10);
50
+ if (Number.isNaN(workchainId)) return null;
51
+ let hex$1 = parts[1];
52
+ if (hex$1.startsWith("0x")) hex$1 = hex$1.slice(2);
53
+ if (hex$1.length !== RAW_HEX_LENGTH) return null;
54
+ if (!/^[0-9a-fA-F]+$/.test(hex$1)) return null;
55
+ const address = new Uint8Array(32);
56
+ for (let i = 0; i < 32; i++) address[i] = parseInt(hex$1.slice(i * 2, i * 2 + 2), 16);
57
+ return {
58
+ workchainId,
59
+ address,
60
+ tag: null
61
+ };
62
+ }
63
+ function tryParseTonAddress(s) {
64
+ if (s.includes(":")) return parseTonRawAddress(s);
65
+ return parseTonUserFriendlyAddress(s);
66
+ }
67
+
68
+ //#endregion
69
+ export { TON_ADDRESS_TAG_BOUNCEABLE_MAINNET, TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET, TON_WORKCHAIN_BASECHAIN, TON_WORKCHAIN_MASTERCHAIN, tryParseTonAddress };
@@ -1,5 +1,6 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  const require_caip2 = require('./caip2.cjs');
3
+ const require_ton_address = require('./ton-address.cjs');
3
4
  let _defuse_protocol_internal_utils = require("@defuse-protocol/internal-utils");
4
5
  let viem = require("viem");
5
6
  let _noble_hashes_sha2 = require("@noble/hashes/sha2");
@@ -244,26 +245,11 @@ function validateTronHexAddress(address) {
244
245
  return false;
245
246
  }
246
247
  }
247
- function crc16ccitt(data) {
248
- let crc = 0;
249
- for (const byte of data) {
250
- crc ^= byte << 8;
251
- for (let i = 0; i < 8; i++) crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
252
- crc &= 65535;
253
- }
254
- return [crc >> 8 & 255, crc & 255];
255
- }
256
248
  function validateTonAddress(address) {
257
- try {
258
- const data = _scure_base.base64urlnopad.decode(address);
259
- if (data.length !== 36) return false;
260
- const tag = data[0];
261
- if (tag !== 17 && tag !== 81) return false;
262
- const [hi, lo] = crc16ccitt(data.subarray(0, 34));
263
- return data[34] === hi && data[35] === lo;
264
- } catch {
265
- return false;
266
- }
249
+ const parsed = require_ton_address.tryParseTonAddress(address);
250
+ if (parsed === null) return false;
251
+ if (parsed.workchainId !== require_ton_address.TON_WORKCHAIN_BASECHAIN && parsed.workchainId !== require_ton_address.TON_WORKCHAIN_MASTERCHAIN) return false;
252
+ return parsed.tag === null || parsed.tag === require_ton_address.TON_ADDRESS_TAG_BOUNCEABLE_MAINNET || parsed.tag === require_ton_address.TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET;
267
253
  }
268
254
  function validateSuiAddress(address) {
269
255
  return /^(?:0x)?[a-fA-F0-9]{64}$/.test(address);
@@ -1,8 +1,9 @@
1
1
  import { Chains } from "./caip2.js";
2
+ import { TON_ADDRESS_TAG_BOUNCEABLE_MAINNET, TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET, TON_WORKCHAIN_BASECHAIN, TON_WORKCHAIN_MASTERCHAIN, tryParseTonAddress } from "./ton-address.js";
2
3
  import { utils } from "@defuse-protocol/internal-utils";
3
4
  import { isAddress } from "viem";
4
5
  import { sha256 } from "@noble/hashes/sha2";
5
- import { base58, base64urlnopad, bech32, bech32m, hex } from "@scure/base";
6
+ import { base58, bech32, bech32m, hex } from "@scure/base";
6
7
  import { PublicKey } from "@solana/web3.js";
7
8
  import { isValidClassicAddress, isValidXAddress } from "ripple-address-codec";
8
9
 
@@ -243,26 +244,11 @@ function validateTronHexAddress(address) {
243
244
  return false;
244
245
  }
245
246
  }
246
- function crc16ccitt(data) {
247
- let crc = 0;
248
- for (const byte of data) {
249
- crc ^= byte << 8;
250
- for (let i = 0; i < 8; i++) crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
251
- crc &= 65535;
252
- }
253
- return [crc >> 8 & 255, crc & 255];
254
- }
255
247
  function validateTonAddress(address) {
256
- try {
257
- const data = base64urlnopad.decode(address);
258
- if (data.length !== 36) return false;
259
- const tag = data[0];
260
- if (tag !== 17 && tag !== 81) return false;
261
- const [hi, lo] = crc16ccitt(data.subarray(0, 34));
262
- return data[34] === hi && data[35] === lo;
263
- } catch {
264
- return false;
265
- }
248
+ const parsed = tryParseTonAddress(address);
249
+ if (parsed === null) return false;
250
+ if (parsed.workchainId !== TON_WORKCHAIN_BASECHAIN && parsed.workchainId !== TON_WORKCHAIN_MASTERCHAIN) return false;
251
+ return parsed.tag === null || parsed.tag === TON_ADDRESS_TAG_BOUNCEABLE_MAINNET || parsed.tag === TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET;
266
252
  }
267
253
  function validateSuiAddress(address) {
268
254
  return /^(?:0x)?[a-fA-F0-9]{64}$/.test(address);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defuse-protocol/intents-sdk",
3
- "version": "0.64.0",
3
+ "version": "0.64.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "repository": {
@@ -53,6 +53,7 @@
53
53
  "@defuse-protocol/internal-utils": "0.32.0"
54
54
  },
55
55
  "devDependencies": {
56
+ "@ton/core": "^0.60.0",
56
57
  "tsdown": "0.19.0"
57
58
  },
58
59
  "scripts": {