@defuse-protocol/intents-sdk 0.64.0 → 0.65.0

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
@@ -39,7 +39,8 @@ const Chains = {
39
39
  Scroll: "eip155:534352",
40
40
  Aleo: "aleo:0",
41
41
  Dash: "bip122:00000ffd590b1485b3caadc19b22e637",
42
- Abstract: "eip155:2741"
42
+ Abstract: "eip155:2741",
43
+ HyperCore: "hlcore:mainnet"
43
44
  };
44
45
  function getEIP155ChainId(chain) {
45
46
  (0, _defuse_protocol_internal_utils.assert)(chain.startsWith("eip155:"), "Chain is not an EIP-155 chain");
@@ -37,6 +37,7 @@ declare const Chains: {
37
37
  readonly Aleo: "aleo:0";
38
38
  readonly Dash: "bip122:00000ffd590b1485b3caadc19b22e637";
39
39
  readonly Abstract: "eip155:2741";
40
+ readonly HyperCore: "hlcore:mainnet";
40
41
  };
41
42
  type Chain = (typeof Chains)[keyof typeof Chains];
42
43
  //#endregion
@@ -37,6 +37,7 @@ declare const Chains: {
37
37
  readonly Aleo: "aleo:0";
38
38
  readonly Dash: "bip122:00000ffd590b1485b3caadc19b22e637";
39
39
  readonly Abstract: "eip155:2741";
40
+ readonly HyperCore: "hlcore:mainnet";
40
41
  };
41
42
  type Chain = (typeof Chains)[keyof typeof Chains];
42
43
  //#endregion
@@ -38,7 +38,8 @@ const Chains = {
38
38
  Scroll: "eip155:534352",
39
39
  Aleo: "aleo:0",
40
40
  Dash: "bip122:00000ffd590b1485b3caadc19b22e637",
41
- Abstract: "eip155:2741"
41
+ Abstract: "eip155:2741",
42
+ HyperCore: "hlcore:mainnet"
42
43
  };
43
44
  function getEIP155ChainId(chain) {
44
45
  assert(chain.startsWith("eip155:"), "Chain is not an EIP-155 chain");
@@ -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");
@@ -48,7 +49,8 @@ function validateAddress(address, blockchain) {
48
49
  case require_caip2.Chains.Berachain:
49
50
  case require_caip2.Chains.Plasma:
50
51
  case require_caip2.Chains.Scroll:
51
- case require_caip2.Chains.Abstract: return validateEthAddress(address);
52
+ case require_caip2.Chains.Abstract:
53
+ case require_caip2.Chains.HyperCore: return validateEthAddress(address);
52
54
  case require_caip2.Chains.Aleo: return validateAleoAddress(address);
53
55
  case require_caip2.Chains.Dash: return validateDashAddress(address);
54
56
  default: return false;
@@ -244,26 +246,11 @@ function validateTronHexAddress(address) {
244
246
  return false;
245
247
  }
246
248
  }
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
249
  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
- }
250
+ const parsed = require_ton_address.tryParseTonAddress(address);
251
+ if (parsed === null) return false;
252
+ if (parsed.workchainId !== require_ton_address.TON_WORKCHAIN_BASECHAIN && parsed.workchainId !== require_ton_address.TON_WORKCHAIN_MASTERCHAIN) return false;
253
+ 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
254
  }
268
255
  function validateSuiAddress(address) {
269
256
  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
 
@@ -47,7 +48,8 @@ function validateAddress(address, blockchain) {
47
48
  case Chains.Berachain:
48
49
  case Chains.Plasma:
49
50
  case Chains.Scroll:
50
- case Chains.Abstract: return validateEthAddress(address);
51
+ case Chains.Abstract:
52
+ case Chains.HyperCore: return validateEthAddress(address);
51
53
  case Chains.Aleo: return validateAleoAddress(address);
52
54
  case Chains.Dash: return validateDashAddress(address);
53
55
  default: return false;
@@ -243,26 +245,11 @@ function validateTronHexAddress(address) {
243
245
  return false;
244
246
  }
245
247
  }
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
248
  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
- }
249
+ const parsed = tryParseTonAddress(address);
250
+ if (parsed === null) return false;
251
+ if (parsed.workchainId !== TON_WORKCHAIN_BASECHAIN && parsed.workchainId !== TON_WORKCHAIN_MASTERCHAIN) return false;
252
+ return parsed.tag === null || parsed.tag === TON_ADDRESS_TAG_BOUNCEABLE_MAINNET || parsed.tag === TON_ADDRESS_TAG_NON_BOUNCEABLE_MAINNET;
266
253
  }
267
254
  function validateSuiAddress(address) {
268
255
  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.65.0",
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": {