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