UNPKG

hapi-ton-sdk

Version:

SDK for managing HAPI attestations on TON network

368 lines (359 loc) 13.3 kB
"use strict"; 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