@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
JavaScript
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;
;