You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript运行TON部署脚本报错:Unknown address type. Byte length is not 36

运行TON部署脚本时遇到"Unknown address type: byte length is not equal to 36"错误

错误日志

yarn ts-node manage/deploy-sandbox.ts
yarn run v1.22.19
$ /Users/apple/proj/tonstart/node_modules/.bin/ts-node manage/deploy-sandbox.ts
/Users/apple/proj/tonstart/node_modules/ton/dist/address/Address.js:17
    throw new Error('Unknown address type: byte length is not equal to 36');
          ^
Error: Unknown address type: byte length is not equal to 36
    at parseFriendlyAddress (/Users/apple/proj/tonstart/node_modules/ton/dist/address/Address.js:17:15)

部署脚本代码(deploy-sandbox.ts)

import { Cell, contractAddress, StateInit, toNano, beginCell, Address } from  'ton';
import { readFileSync } from 'fs';
import qs from 'qs';
import qrcode from 'qrcode-terminal';

// Create a data cell similar to the initial contract state
const dataCell = beginCell()
.storeUint(0, 32)                        // counter
.storeAddress(Address.parse('/* YOUR ADDRESS */'))
.endCell();

// Load code from build
const codeCell = Cell.fromBoc(readFileSync('./build/hello-world.boc'))[0];

// Calculate address from code & data
const address = contractAddress({
    workchain: 0,
    initialCode: codeCell,
    initialData: dataCell
});

// Prepare init message
const initCell = new Cell();
new StateInit({
code: codeCell,
data: dataCell,
}).writeTo(initCell);

// Encode link to deploy contract
let link = 'https://test.tonhub.com/transfer/' + address.toFriendly({ testOnly: true }) + '?' + qs.stringify({
text: 'Deploy contract',
amount: toNano(1).toString(10),
init: initCell.toBoc({ idx: false }).toString('base64')
});
console.log('Address: ' + address.toFriendly({ testOnly: true }));
qrcode.generate(link, { small: true }, (code) => {
 console.log(code)
});

Address类型定义(Address.d.ts)

/// <reference types="node" />
import inspectSymbol from 'symbol.inspect';
export declare class Address {
    static isAddress(src: any): src is Address;
    static isFriendly(source: String): boolean;
    static normalize(source: string | Address):  string;
   static parse(source: string): Address;
   static parseRaw(source: string): Address;
   static parseFriendly(source: string | Buffer): {
        isBounceable: boolean;
        isTestOnly: boolean;
    address: Address;
   };
   readonly workChain: number;
   readonly hash: Buffer;
   constructor(workChain: number, hash: Buffer);
    toString: () => string;
    equals(src: Address): boolean;
    toBuffer: () => Buffer;
    toFriendlyBuffer: (args?: {
    bounceable?: boolean | undefined;
    testOnly?: boolean | undefined;
    } | undefined) => Buffer;
    toFriendly: (args?: {
        urlSafe?: boolean | undefined;
        bounceable?: boolean | undefined;
        testOnly?: boolean | undefined;
   } | undefined) => string;

Address实现代码(Address.js)

"use strict";
var __importDefault = (this && this.__importDefault)    || function (mod) {
return (mod && mod.__esModule) ? mod : { "default":   mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value:  true });
exports.Address = void 0;
const symbol_inspect_1 =    __importDefault(require("symbol.inspect"));
const crc16_1 = require("../utils/crc16");
const bounceable_tag = 0x11;
const non_bounceable_tag = 0x51;
const test_flag = 0x80;
function parseFriendlyAddress(src) {
    const data = Buffer.isBuffer(src) ? src :     Buffer.from(src, 'base64');
    // 1byte tag + 1byte workchain + 32 bytes hash +    2 byte crc
    if (data.length !== 36) {
        throw new Error('Unknown address type: byte    length is not equal to 36');
    }
// Prepare data
const addr = data.slice(0, 34);
const crc = data.slice(34, 36);
const calcedCrc = (0, crc16_1.crc16)(addr);
if (!(calcedCrc[0] === crc[0] && calcedCrc[1] === crc[1])) {
    throw new Error('Invalid checksum: ' + src);
}
// Parse tag
let tag = addr[0];
let isTestOnly = false;
let isBounceable = false;
if (tag & test_flag) {
    isTestOnly = true;
    tag = tag ^ test_flag;
}
if ((tag !== bounceable_tag) && (tag !==  non_bounceable_tag))
    throw "Unknown address tag";
isBounceable = tag === bounceable_tag;
let workchain = null;
if (addr[1] === 0xff) { // TODO we should read signed    integer here
    workchain = -1;
}
else {
    workchain = addr[1];
}
const hashPart = addr.slice(2, 34);
return { isTestOnly, isBounceable, workchain,   hashPart };
}
class Address {
constructor(workChain, hash) {
    this.toString = () => {
        return this.workChain + ':' +   this.hash.toString('hex');
    };
    this.toBuffer = () => {
        const addressWithChecksum = Buffer.alloc(36);
        addressWithChecksum.set(this.hash);
        addressWithChecksum.set([this.workChain,   this.workChain, this.workChain, this.workChain], 32);
        return addressWithChecksum;
    };
    this.toFriendlyBuffer = (args) => {
        let testOnly = (args && args.testOnly !==   undefined) ? args.testOnly : false;
        let bounceable = (args && args.bounceable !==  undefined) ? args.bounceable : true;
        let tag = bounceable ? bounceable_tag : non_bounceable_tag;
        if (testOnly) {
            tag |= test_flag;
        }
        const addr = Buffer.alloc(34);
        addr[0] = tag;
        addr[1] = this.workChain;
        addr.set(this.hash, 2);
        const addressWithChecksum = Buffer.alloc(36);
        addressWithChecksum.set(addr);
        addressWithChecksum.set((0, crc16_1.crc16) (addr), 34);
        return addressWithChecksum;
    };
    this.toFriendly = (args) => {
        let urlSafe = (args && args.urlSafe !== undefined) ? args.urlSafe : true;
        let buffer = this.toFriendlyBuffer(args);
        if (urlSafe) {
            return      buffer.toString('base64').replace(/\+/g, '-  ').replace(/\//g, '_');
        }
        else {
            return buffer.toString('base64');
        }
    };
    this[_a] = () => this.toFriendly();
    this.workChain = workChain;
    this.hash = hash;
    Object.freeze(this);
}
static isAddress(src) {
    return src instanceof Address;
}
static isFriendly(source) {
    return source.indexOf(':') < 0;
}
static normalize(source) {
    if (typeof source === 'string') {
        return Address.parse(source).toFriendly();
    }
    else {
        return source.toFriendly();
    }
}
static parse(source) {
    if (Address.isFriendly(source)) {
        return this.parseFriendly(source).address;
    }
    else {
        return this.parseRaw(source);
    }
}
static parseRaw(source) {
    let workChain = parseInt(source.split(":")[0]);
    let hash = Buffer.from(source.split(":")[1],     'hex');
    return new Address(workChain, hash);
}
static parseFriendly(source) {
    if (Buffer.isBuffer(source)) {
        let r = parseFriendlyAddress(source);
        return {
            isBounceable: r.isBounceable,
            isTestOnly: r.isTestOnly,
            address: new Address(r.workchain,  r.hashPart)
        };
    }
       else {
           let addr = source.replace(/\-/g,   '+').replace(/\_/g, '\/'); // Convert from url-friendly to    true base64
        let r = parseFriendlyAddress(addr);
        return {
            isBounceable: r.isBounceable,
            isTestOnly: r.isTestOnly,
            address: new Address(r.workchain,    r.hashPart)
        };
    }
}
equals(src) {
        if (src.workChain !== this.workChain) {
            return false;
        }
        return src.hash.equals(this.hash);
    }
}
exports.Address = Address;
_a = symbol_inspect_1.default;

错误原因及解决方法

原因

脚本中Address.parse('/* YOUR ADDRESS */')使用了占位符字符串,并非有效的TON地址。Address.parse会先判断字符串是否为友好地址(不含冒号),然后调用parseFriendly解析。占位符转base64后的buffer长度远不等于36,触发parseFriendlyAddress中的长度检查报错。

解决步骤

  1. 替换占位符为有效测试网地址:
    • 支持两种格式的地址:
      • 原始格式:例如0:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890(工作链ID+64位十六进制哈希)
      • 友好格式:例如EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N(TON测试网的base64编码地址)
  2. 获取测试网地址:
    • 如果没有测试网地址,可通过TON官方钱包创建测试网账户,导出对应地址即可。

修改后的代码片段示例:

const dataCell = beginCell()
.storeUint(0, 32)                        // counter
.storeAddress(Address.parse('EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N')) // 替换为你的测试网地址
.endCell();

内容的提问来源于stack exchange,提问作者Draco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:05:24