UNPKG

@firefly-exchange/library-sui

Version:

Sui library housing helper methods, classes to interact with Bluefin protocol(s) deployed on Sui

143 lines (142 loc) 5.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Quote = exports.Signature = exports.BcsQuote = void 0; const bcs_1 = require("@mysten/sui/bcs"); const library_1 = require("../library"); const types_1 = require("../types"); const v3_1 = require("../v3"); const bcs_2 = require("@mysten/bcs"); const helpers_1 = require("../helpers"); const classes_1 = require("../classes"); const cryptography_1 = require("@mysten/sui/cryptography"); const ed25519_1 = require("@noble/curves/ed25519"); const utils_1 = require("../utils"); const sha256_1 = require("@noble/hashes/sha256"); exports.BcsQuote = bcs_1.bcs.struct("Quote", { vault: bcs_1.bcs.Address, id: bcs_1.bcs.string(), taker: bcs_1.bcs.Address, token_in_amount: bcs_1.bcs.u64(), token_out_amount: bcs_1.bcs.u64(), token_in_type: bcs_1.bcs.string(), token_out_type: bcs_1.bcs.string(), expires_at: bcs_1.bcs.u64(), created_at: bcs_1.bcs.u64() }); exports.Signature = bcs_1.bcs.struct("Signature", { sig: bcs_1.bcs.vector(bcs_1.bcs.u8()), pk: bcs_1.bcs.vector(bcs_1.bcs.u8()), scheme: bcs_1.bcs.u8() }); class Quote { constructor(quote) { this.quote = quote; } /** * * @param vault The id of the vault for which the quote is fo * @param account The account for which the quote is being created * @param token_in_amount The amount of token that will be going into the vault * @param token_out_amount The amount of output token the user will get (excludes protocol fee) * @param token_in_type The token/coin type of the input token * @param token_out_type The token/coin type of the output token * @param options optional arguments * @returns Quote */ static new(vault, taker, token_in_amount, token_out_amount, token_in_type, token_out_type, options) { const id = options?.id || (0, v3_1.getRandomString)(1); const created_at = options?.created_at || Date.now(); const expires_at = options?.expires_at || Number(created_at) + 1000000; return new Quote({ vault, id, taker, token_in_amount: (0, library_1.bigNumber)(token_in_amount).toString(), token_out_amount: (0, library_1.bigNumber)(token_out_amount).toString(), token_in_type, token_out_type, expires_at, created_at }); } /** * Bcs serializes the quote and returns its BCS representation * @returns BCS serialized Uint8Array of the quote */ serialize() { return exports.BcsQuote.serialize(this.quote).toBytes(); } /** * Signs the quote * @param signer The manager of the vault. Must be ED25519 or Secp wallet, other * wallets are not supported like Multisig, ZK * @returns Returns a base64 representation of signature containing: * 1. scheme (1 byte), * 2. signature (64 bytes) * 3. public key (32/33 bytes) */ async sign(signer) { const signature = await signer.sign(this.serialize()); const signatureBytes = Buffer.from(signature); const pkBytes = Buffer.from(signer.getPublicKey().toRawBytes()); const scheme = Buffer.from(signer.getKeyScheme() == "ED25519" ? [0] : [1]); const combined = Buffer.concat([scheme, signatureBytes, pkBytes]); return combined.toString("base64"); } /** * Validates if the signature is for the provided quote * @param signature The base64 signature * @param signer The expected address of the signer * @returns True if the signature is created on the given quote and the sig creator is the one provided */ async verify(signature, signer) { try { const parsed = (0, cryptography_1.parseSerializedSignature)(signature); let verified = false; if (parsed.signatureScheme == "ED25519") { verified = ed25519_1.ed25519.verify(Buffer.from(parsed.signature).toString("hex"), Buffer.from(this.serialize()).toString("hex"), Buffer.from(parsed.publicKey).toString("hex")); } else if (parsed.signatureScheme == "Secp256k1") { verified = (0, utils_1.verifySECP)(Buffer.from(parsed.signature).toString("hex"), (0, sha256_1.sha256)(this.serialize()), parsed.publicKey); } else { throw `Signature is created using invalid signer type: ${parsed.signatureScheme}`; } if (!verified) return false; return (signer == (0, library_1.getSuiAddressFromPublicKey)(parsed.publicKey, parsed.signatureScheme)); } catch (e) { return false; } } /** * Performs a dry run contract call to verify the signature on-chain * @param signature The signature to be verified * @param client The Sui client * @param pkg The contract pkg to be used * @param verbose optional * @returns boolean */ async onChainVerify(signature, client, pkg, verbose = false) { const txb = new types_1.TransactionBlock(); txb.moveCall({ arguments: [ txb.pure.vector("u8", Array.from(this.serialize())), txb.pure.vector("u8", Array.from((0, bcs_2.fromBase64)(signature))) ], target: `${pkg}::vault::verify_signature` }); const result = await client.devInspectTransactionBlock({ transactionBlock: txb, sender: helpers_1.TEST_WALLETS[0].address }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const status = classes_1.Transaction.getStatus(result); if (verbose) console.log(JSON.stringify(result)); return status == "success"; } } exports.Quote = Quote;