UNPKG

@firefly-exchange/library-sui

Version:

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

221 lines (220 loc) 10.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OrderSigner = void 0; const bcs_1 = require("@mysten/sui/bcs"); const cryptography_1 = require("@mysten/sui/cryptography"); const ed25519_1 = require("@noble/curves/ed25519"); const blake2b_1 = require("@noble/hashes/blake2b"); const sha256_1 = require("@noble/hashes/sha256"); const enums_1 = require("../enums"); const library_1 = require("../library"); const utils_1 = require("../utils"); const bs58_1 = __importDefault(require("bs58")); const tweetnacl_1 = require("tweetnacl"); class OrderSigner { constructor(signer) { this.signer = signer; } async getSignedOrder(order, signer) { const typedSignature = await this.signOrder(order, signer); return { ...order, typedSignature: `${typedSignature.signature}${typedSignature.publicKey}` }; } async signOrder(order, signer) { const caller = signer || this.signer; // serialize order const msgData = new TextEncoder().encode(OrderSigner.getSerializedOrder(order)); // take sha256 hash of order const msgHash = (0, sha256_1.sha256)(msgData); const publicKey = caller.getPublicKey().toBase64(); const keyScheme = caller.getKeyScheme(); let signatureType = null; let signatureInput = null; if (keyScheme == "Secp256k1") { // sign the raw data signatureType = enums_1.SIGNER_TYPES.KP_SECP256; signatureInput = msgData; } else if (keyScheme == "ED25519") { // in case of ed25519 we sign the hashed msg signatureType = enums_1.SIGNER_TYPES.KP_ED25519; signatureInput = msgHash; } else { throw "Invalid wallet type"; } const sign = await caller.sign(signatureInput); const signature = Buffer.from(sign).toString("hex") + signatureType; return { signature, publicKey }; } static async signOrderUsingZkSignature({ order, signer, zkPayload }) { // serialize order const msgData = new TextEncoder().encode(OrderSigner.getSerializedOrder(order)); // take sha256 hash of order const msgHash = (0, sha256_1.sha256)(msgData); // sign data const { signature } = await signer.signPersonalMessage(msgHash); const zkSignature = (0, utils_1.createZkSignature)({ userSignature: signature, zkPayload }); return (0, utils_1.parseAndShapeSignedData)({ signature: zkSignature }); } /** * Signs the order using the provided wallet context * @param order order to be signed * @param wallet wallet context * @returns signature and public key */ static async signOrderUsingWallet(order, wallet) { // serialize order const msgData = new TextEncoder().encode(OrderSigner.getSerializedOrder(order)); // take sha256 hash of order const msgHash = (0, sha256_1.sha256)(msgData); // sign data const { signature } = await wallet.signPersonalMessage({ message: msgHash }); return (0, utils_1.parseAndShapeSignedData)({ signature }); } async signPayload(payload, keyPair) { const signer = keyPair || this.signer; const encodedData = OrderSigner.encodePayload(payload); const publicKey = signer.getPublicKey().toBase64(); const keyScheme = signer.getKeyScheme(); let signatureType = null; if (keyScheme == "Secp256k1") { signatureType = enums_1.SIGNER_TYPES.KP_SECP256; } else if (keyScheme == "ED25519") { signatureType = enums_1.SIGNER_TYPES.KP_ED25519; } else { throw "Invalid wallet type"; } const sign = await signer.sign(encodedData); const signature = Buffer.from(sign).toString("hex") + signatureType; return { signature, publicKey }; } static async signPayloadUsingZKSignature({ payload, signer, zkPayload }) { const msgBytes = new TextEncoder().encode(JSON.stringify(payload)); const { signature } = await signer.signPersonalMessage(msgBytes); const zkSignature = (0, utils_1.createZkSignature)({ userSignature: signature, zkPayload }); return (0, utils_1.parseAndShapeSignedData)({ signature: zkSignature }); } static async signBytesPayloadUsingZKSignature({ payload, signer, zkPayload }) { const { signature } = await signer.signPersonalMessage(payload); const zkSignature = (0, utils_1.createZkSignature)({ userSignature: signature, zkPayload }); return (0, utils_1.parseAndShapeSignedData)({ signature: zkSignature }); } static async signPayloadUsingWallet(payload, wallet, useDeprecatedSigningMethod) { const msgBytes = new TextEncoder().encode(JSON.stringify(payload)); // Doing this to support Gate Wallet which does not support SignPersonalMessage if (useDeprecatedSigningMethod) { const { signature } = await wallet.signMessage({ message: msgBytes }); return (0, utils_1.parseAndShapeSignedData)({ signature }); } const { signature } = await wallet.signPersonalMessage({ message: msgBytes }); return (0, utils_1.parseAndShapeSignedData)({ signature }); } static encodePayload(payload, intentScope = "PersonalMessage") { const msgBytes = new TextEncoder().encode(JSON.stringify(payload)); const size = 1024 + Math.floor(msgBytes.length / 1024) * 1024; const intentMsg = (0, cryptography_1.messageWithIntent)(intentScope, bcs_1.bcs.vector(bcs_1.bcs.U8).serialize(msgBytes).toBytes()); const encodeData = (0, blake2b_1.blake2b)(intentMsg, { dkLen: 32 }); return encodeData; } static verifySignature(payload, signature, publicKey) { const encodedData = OrderSigner.encodePayload(payload); const pkBytes = (0, library_1.base64ToUint8)(publicKey); // if last index of string is zero, the signature is generated using secp wallet const char = signature.slice(-1); // remove last character/index from signature signature = signature.slice(0, -1); if (char == enums_1.SIGNER_TYPES.KP_SECP256) { return (0, utils_1.verifySECP)(signature, (0, sha256_1.sha256)(encodedData), pkBytes); } else if (char == enums_1.SIGNER_TYPES.KP_ED25519 || char == enums_1.SIGNER_TYPES.UI_ED25519) { return ed25519_1.ed25519.verify(signature, encodedData, pkBytes); } else { throw "Invalid signature type"; } } static verifyPhantomWalletSignature(payload, signature, publicKey) { const pkBytes = bs58_1.default.decode(publicKey); const encodedData = new TextEncoder().encode(JSON.stringify(payload)); const sigBytes = new Uint8Array(Buffer.from(signature, "hex")); return tweetnacl_1.sign.detached.verify(encodedData, sigBytes, pkBytes); } /** * Verifies if the given signature is correct or not using the raw order * @param order the order used to create the signature * @param signature the generated signature in hex string * @param publicKey signer's public key in base64 str * @returns True if the signature is valid */ static verifySignatureUsingOrder(order, signature, publicKey) { const serializedOrder = OrderSigner.getSerializedOrder(order); const encodedOrder = new TextEncoder().encode(serializedOrder); const orderHash = (0, sha256_1.sha256)(encodedOrder); const pkBytes = (0, library_1.base64ToUint8)(publicKey); // if last index of string is zero, the signature is generated using secp wallet const char = signature.slice(-1); // remove last character/index from signature signature = signature.slice(0, -1); if (char == enums_1.SIGNER_TYPES.KP_SECP256) { return (0, utils_1.verifySECP)(signature, orderHash, pkBytes); } else if (char == enums_1.SIGNER_TYPES.KP_ED25519) { return ed25519_1.ed25519.verify(signature, orderHash, pkBytes); } else if (char == enums_1.SIGNER_TYPES.UI_ED25519) { const intentMsg = (0, cryptography_1.messageWithIntent)("PersonalMessage", bcs_1.bcs.vector(bcs_1.bcs.U8).serialize(orderHash).toBytes()); const signedData = (0, blake2b_1.blake2b)(intentMsg, { dkLen: 32 }); return ed25519_1.ed25519.verify(signature, signedData, pkBytes); } return false; } static getSerializedOrder(order) { // encode order flags const orderFlags = (0, library_1.encodeOrderFlags)(order); const buffer = Buffer.alloc(144); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(order.price)), 0); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(order.quantity)), 16); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(order.leverage)), 32); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(order.salt)), 48); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(order.expiration, 16)), 64); buffer.set((0, library_1.hexToBuffer)(order.maker), 72); buffer.set((0, library_1.hexToBuffer)(order.market), 104); buffer.set((0, library_1.hexToBuffer)((0, library_1.bnToHex)(orderFlags, 2)), 136); buffer.set(Buffer.from("Bluefin", "utf8"), 137); return buffer.toString("hex"); } static getOrderHash(order) { // if serialized order is not provided if (typeof order !== "string") { order = OrderSigner.getSerializedOrder(order); } const hash = (0, sha256_1.sha256)((0, library_1.hexToBuffer)(order)); return Buffer.from(hash).toString("hex"); } getPublicKeyStr(keypair) { const signer = keypair || this.signer; return signer.getPublicKey().toBase64(); } } exports.OrderSigner = OrderSigner;