hapi-ton-sdk
Version:
SDK for managing HAPI attestations on TON network
368 lines (359 loc) • 13.3 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
HapiSDK: () => HapiSDK,
HapiTonAttestation: () => HapiTonAttestation,
OpCode: () => OpCode,
TON_DEFAULT_GAS: () => TON_DEFAULT_GAS,
TON_MIN_COMMISSION: () => TON_MIN_COMMISSION,
TON_MIN_JETTON_STORAGE: () => TON_MIN_JETTON_STORAGE,
UserTonJetton: () => UserTonJetton,
config: () => config,
delay: () => delay
});
module.exports = __toCommonJS(index_exports);
// src/utils/crc32.ts
function crc32(str) {
const table = new Int32Array(256);
for (let i = 0; i < 256; i++) {
let c = i;
for (let j = 0; j < 8; j++) {
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
}
table[i] = c;
}
let crc = -1;
for (let i = 0; i < str.length; i++) {
crc = crc >>> 8 ^ table[(crc ^ str.charCodeAt(i)) & 255];
}
return (crc ^ -1) >>> 0;
}
// src/types/index.ts
var OpCode = {
createAttestation: crc32("create_attestation"),
updateAttestation: crc32("update_attestation")
};
// src/contracts/HapiAttestation.ts
var import_core = require("@ton/core");
// src/config.ts
var config = {
apiStaging: "https://hapi-one.stage.hapi.farm",
apiProduction: "https://score-be.hapi.mobi",
ton: {
score: "kQC60vGFCtYeQi-S0p6Lhfghd0vYS1YcTiHDWhEmuQ39QpCh",
nodeUrl: "https://tonapi.io"
},
tonTestnet: {
score: "kQC60vGFCtYeQi-S0p6Lhfghd0vYS1YcTiHDWhEmuQ39QpCh",
nodeUrl: "https://testnet.tonapi.io"
},
tonApiPath: (hash) => `/v2/blockchain/messages/${hash}/transaction`
};
// src/contracts/HapiAttestation.ts
var HapiTonAttestation = class _HapiTonAttestation {
constructor(address, init) {
this.address = address;
this.init = init;
}
static createFromAddress(address = config.ton.score, contractAdapter) {
return contractAdapter.open(new _HapiTonAttestation((0, import_core.address)(address)));
}
async getCreateAttestationFee(provider) {
const result = await provider.get("get_create_attestation_fee", []);
return result.stack.readBigNumber();
}
async getUpdateAttestationFee(provider) {
const result = await provider.get("get_update_attestation_fee", []);
return result.stack.readBigNumber();
}
async getAttestationData(provider) {
const res = await provider.get("get_hapi_attestation_data", []);
const userCount = res.stack.readBigNumber();
const contractOwner = res.stack.readAddress();
const commissionOwner = res.stack.readAddress();
const createAttestatioFee = res.stack.readBigNumber();
const updateAttestatioFee = res.stack.readBigNumber();
const walletCode = res.stack.readCell();
return {
userCount,
contractOwner,
commissionOwner,
createAttestatioFee,
updateAttestatioFee,
walletCode
};
}
static async getUserJettonAddress(provider, address) {
const result = await provider.get("get_user_jetton_address", [
{
type: "slice",
cell: (0, import_core.beginCell)().storeAddress((0, import_core.address)(address)).endCell()
}
]);
return result.stack.readAddress();
}
static getStaticUserJettonAddress(address) {
const JETTON_WALLET_CODE = import_core.Cell.fromBoc(
Buffer.from(
"b5ee9c724102140100013b000114ff00f4a413f4bcf2c80b01020120021302014803070202cb040602dfd0ccc7434c0c05c6c2456f80871c02456f83e900c36cf1b088134c7c860842576e74e6ea497c1b81450b1c17cb87d208433e45309eea3ac40b4cfc0407481f4cffe803e900c208203d0901c3ec08076cf08d04d8572140173c584f2c1f2cfc073c5b3327b55007c057817c12103fcbc212050028c8801001cb0558cf1601fa027001cb6ac973fb000049a2e4400800e58280e78b387d013800e5b541086a993b6d80e58f8080e59fe4c080417d80400201480811020120090e0201480a0b0111ae56ed9e08122f8240120201200c0d0110a9d4db3c10345f0412010aa9bfdb3c30120201580f10000fad97fc13b7911840010dacd2ed9e2f824012010fb9996db3c145f04812001aed44d0fa40d207d33ffa40d430000cf230840ff2f0a35e372c",
"hex"
)
)[0];
const JETTON_MASTER_ADDRESS = import_core.Address.parse(config.ton.score);
const USER_ADDRESS = import_core.Address.parse(address);
const USER_ADDRESS_CELL = (0, import_core.beginCell)().storeAddress(USER_ADDRESS).endCell();
const JETTON_MASTER_ADDRESS_CELL = (0, import_core.beginCell)().storeAddress(JETTON_MASTER_ADDRESS).endCell();
const userJettonWalletData = (0, import_core.beginCell)().storeSlice(USER_ADDRESS_CELL.asSlice()).storeUint(0, 8).storeUint(0, 64).storeSlice(JETTON_MASTER_ADDRESS_CELL.asSlice()).storeRef(JETTON_WALLET_CODE).endCell();
const jettonWalletStateInit = (0, import_core.beginCell)().storeUint(0, 2).storeMaybeRef(JETTON_WALLET_CODE).storeMaybeRef(userJettonWalletData).storeUint(0, 1).endCell();
return new import_core.Address(0, jettonWalletStateInit.hash());
}
prepareCreateAttestation(opts) {
return {
value: opts.value,
sendMode: import_core.SendMode.PAY_GAS_SEPARATELY,
body: (0, import_core.beginCell)().storeUint(OpCode.createAttestation, 32).storeUint(opts.queryId, 64).storeUint(opts.referralId ?? 0n, 64).storeUint(opts.trustScore, 8).storeUint(opts.expirationDate, 64).storeBuffer(opts.signature).endCell()
};
}
async sendCreateAttestation(provider, via, opts) {
await provider.internal(via, this.prepareCreateAttestation(opts));
}
prepareUpdateAttestation(opts) {
return {
value: opts.value,
sendMode: import_core.SendMode.PAY_GAS_SEPARATELY,
body: (0, import_core.beginCell)().storeUint(OpCode.updateAttestation, 32).storeUint(opts.queryId, 64).storeUint(opts.referralId ?? 0n, 64).storeUint(opts.trustScore, 8).storeUint(opts.expirationDate, 64).storeBuffer(opts.signature).endCell()
};
}
async sendUpdateAttestation(provider, via, opts) {
await provider.internal(via, this.prepareUpdateAttestation(opts));
}
};
// src/contracts/UserJetton.ts
var UserTonJetton = class _UserTonJetton {
constructor(address, init) {
this.address = address;
this.init = init;
}
static createFromAddress(address, contractAdapter) {
return contractAdapter.open(new _UserTonJetton(address));
}
async getBalance(provider) {
const result = await provider.get("get_smc_balance", []);
return result.stack.readBigNumber();
}
async getOwner(provider) {
const result = await provider.get("get_owner", []);
return result.stack.readAddress();
}
async getAttestationAddress(provider) {
const result = await provider.get("get_attestation_address", []);
return result.stack.readAddress();
}
async getTrustScore(provider) {
const result = await provider.get("get_trust_score", []);
return result.stack.readNumber();
}
async getExpirationDate(provider) {
const result = await provider.get("get_expiration_date", []);
return result.stack.readNumber();
}
async getAttestationData(provider) {
const res = await provider.get("get_user_data", []);
const commissionOwner = res.stack.readAddress();
const trustScore = res.stack.readBigNumber();
const expirationDate = res.stack.readBigNumber();
const attestationAddress = res.stack.readAddress();
return {
commissionOwner,
trustScore,
expirationDate,
attestationAddress
};
}
};
// src/utils/index.ts
var import_core2 = require("@ton/core");
var delay = async (time = 1e3) => {
return new Promise((res) => setTimeout(res, time));
};
var TON_DEFAULT_GAS = (0, import_core2.toNano)("0.05");
var TON_MIN_COMMISSION = (0, import_core2.toNano)("0.01");
var TON_MIN_JETTON_STORAGE = (0, import_core2.toNano)("0.001");
// src/core/HapiSDK.ts
var import_axios = __toESM(require("axios"));
var HapiSDK = class {
constructor(args) {
this.config = {
hapiEndpoint: args.staging ? config.apiStaging : config.apiProduction,
contractAddress: config.ton.score,
nodeUrl: args.testnet ? config.tonTestnet.nodeUrl : config.ton.nodeUrl,
network: args.testnet ? -3 : -239,
referralId: args.referralId,
tonApiKey: args.tonApiKey
};
}
async getUser(jwt) {
try {
const response = await import_axios.default.get(
`${this.config.hapiEndpoint}/ref/v2/get-user`,
{
headers: {
Authorization: `Bearer ${jwt}`
}
}
);
return response.data;
} catch (error) {
throw new Error(`Failed to get user: ${error}`);
}
}
async getTrustScore(address, network, jwt) {
try {
const response = await import_axios.default.post(
`${this.config.hapiEndpoint}/ref/v2/score`,
{
address,
network
},
{
headers: {
Authorization: `Bearer ${jwt}`
}
}
);
return response.data;
} catch (error) {
throw new Error(`Failed to get trust score: ${error}`);
}
}
async getMessage() {
try {
const response = await import_axios.default.get(
`${this.config.hapiEndpoint}/ref/v2/ton-payload`
);
return response.data;
} catch (error) {
throw new Error(`Failed to get ton payload: ${error}`);
}
}
async checkProof({
proof,
address,
network
}) {
return import_axios.default.post(`${this.config.hapiEndpoint}/ref/v2/ton-login`, {
proof,
address,
network
});
}
static async getUserAttestationOnchain(userAddress, contractAdapter) {
try {
const jettonAddress = HapiTonAttestation.getStaticUserJettonAddress(userAddress);
const jettonContract = UserTonJetton.createFromAddress(
jettonAddress,
contractAdapter
);
const attestationData = await jettonContract.getAttestationData();
return {
jettonAddress,
attestationData
};
} catch (error) {
throw new Error(`Failed to get user attestation data: ${error}`);
}
}
async trackAttestationResult(transactionMessageHash, timeInterval = 7e3, maxRetries = 9) {
let attempt = 0;
let status = null;
let data;
while (attempt < maxRetries) {
try {
await delay(timeInterval);
const transactionData = await import_axios.default.get(
this.config.nodeUrl + config.tonApiPath(transactionMessageHash)
);
if (transactionData.status === 200 && transactionData.data.hash) {
status = true;
try {
await import_axios.default.post(
`${this.config.hapiEndpoint}/ref/v2/ref_transaction`,
{
hash: transactionData.data.hash,
network: this.config.network
},
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.config.tonApiKey}`
}
}
);
} catch (error) {
console.error("Error updating attestation count:", error);
}
break;
} else {
status = false;
}
} catch (error) {
console.error(`Error: while get locating transaction`, error);
}
attempt++;
}
return { status, data };
}
async calculateTransactionFee(isUpdate, contractAdapter) {
try {
const hapiContract = HapiTonAttestation.createFromAddress(
this.config.contractAddress,
contractAdapter
);
const fee = isUpdate ? await hapiContract.getUpdateAttestationFee() : await hapiContract.getCreateAttestationFee();
return isUpdate ? fee + TON_DEFAULT_GAS + TON_MIN_COMMISSION : fee + TON_DEFAULT_GAS + TON_MIN_COMMISSION + TON_MIN_JETTON_STORAGE;
} catch (error) {
throw new Error(`Failed to calculate transaction fee: ${error}`);
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
HapiSDK,
HapiTonAttestation,
OpCode,
TON_DEFAULT_GAS,
TON_MIN_COMMISSION,
TON_MIN_JETTON_STORAGE,
UserTonJetton,
config,
delay
});
//# sourceMappingURL=index.js.map