UNPKG

@mysten/sui

Version:
67 lines (65 loc) 2.45 kB
import { normalizeSuiAddress } from "./sui-types.mjs"; import { TypeTagSerializer } from "../bcs/type-tag-serializer.mjs"; import { bcs as suiBcs } from "../bcs/index.mjs"; import { deriveDynamicFieldID } from "./dynamic-fields.mjs"; import { ObjectRefSchema } from "../transactions/data/internal.mjs"; import { fromBase58, fromHex, toBase58, toHex } from "@mysten/bcs"; import { parse } from "valibot"; //#region src/utils/coin-reservation.ts const SUI_ACCUMULATOR_ROOT_OBJECT_ID = normalizeSuiAddress("0xacc"); const ACCUMULATOR_KEY_TYPE_TAG = TypeTagSerializer.parseFromStr("0x2::accumulator::Key<0x2::balance::Balance<0x2::sui::SUI>>"); const COIN_RESERVATION_MAGIC = new Uint8Array([ 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172 ]); function isCoinReservationDigest(digestBase58) { return fromBase58(digestBase58).slice(12, 32).every((byte, i) => byte === COIN_RESERVATION_MAGIC[i]); } /** * Derives the accumulator dynamic field object ID for the given owner, * then XORs it with the chain identifier bytes to produce the objectId * for the coin reservation ref. */ function deriveReservationObjectId(owner, chainIdentifier) { const accBytes = fromHex(deriveDynamicFieldID(SUI_ACCUMULATOR_ROOT_OBJECT_ID, ACCUMULATOR_KEY_TYPE_TAG, suiBcs.Address.serialize(owner).toBytes()).slice(2)); const chainBytes = fromBase58(chainIdentifier); if (chainBytes.length !== 32) throw new Error(`Invalid chain identifier length: expected 32 bytes, got ${chainBytes.length}`); const xored = new Uint8Array(32); for (let i = 0; i < 32; i++) xored[i] = accBytes[i] ^ chainBytes[i]; return `0x${toHex(xored)}`; } function createCoinReservationRef(reservedBalance, owner, chainIdentifier, epoch) { const digestBytes = new Uint8Array(32); const view = new DataView(digestBytes.buffer); view.setBigUint64(0, reservedBalance, true); const epochNum = Number(epoch); if (!Number.isSafeInteger(epochNum) || epochNum < 0 || epochNum > 4294967295) throw new Error(`Epoch ${epoch} out of u32 range for coin reservation digest`); view.setUint32(8, epochNum, true); digestBytes.set(COIN_RESERVATION_MAGIC, 12); return parse(ObjectRefSchema, { objectId: deriveReservationObjectId(owner, chainIdentifier), version: "0", digest: toBase58(digestBytes) }); } //#endregion export { createCoinReservationRef, isCoinReservationDigest }; //# sourceMappingURL=coin-reservation.mjs.map