@debridge-finance/solana-utils
Version:
Common utils package to power communication with Solana contracts at deBridge
140 lines • 5.89 kB
JavaScript
import { Buffer } from "buffer";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { keccak256 as rawKeccak256 } from "js-sha3";
import { hexToBuffer } from "./helpers";
import { isBuffer, } from "./interfaces";
import { DEPLOY_INFO_PREFIX, SUBMISSION_PREFIX } from "./constants";
import { solidityPack } from "./solidityPack";
export const keccak256 = (data) => `0x${rawKeccak256(data)}`;
export const solidityKeccak256 = (types, values) => {
const packed = solidityPack(types, values);
return keccak256(packed);
};
export function denormalizeAmount(amount, denominator) {
const denominatorBN = new BN(Math.pow(10, denominator));
return amount.mul(denominatorBN).toArrayLike(Buffer, "be", 32);
}
export function normalizeChainId(chainId) {
return hexToBuffer(`0x${isBuffer(chainId) ? chainId.toString("hex") : new BN(chainId).toString(16)}`, 32);
}
/**
* Hashes deploy info
* @param params {@link HashDeployInfoParams}
* @returns keccak256 of deployInfo structure
*/
export function hashDeployInfo(params) {
const nameHash = solidityKeccak256(["string"], [params.tokenName]);
const symbolHash = solidityKeccak256(["string"], [params.tokenSymbol]);
const deployInfoHash = solidityKeccak256(["uint256", "uint256", "uint256", "uint256", "uint8"], [
DEPLOY_INFO_PREFIX,
params.debridgeId,
nameHash,
symbolHash,
params.decimals,
]);
return deployInfoHash;
}
/**
* Returns bridgeid hash
* @param nativeChainId chain id where token originates
* @param nativeTokenAddress address of token in native chain in format "0x<HEX STRING>"
* @returns bridge id in deBridge network
*/
export function hashDebridgeId(nativeChainId, nativeTokenAddress) {
const chainIdBuffer = normalizeChainId(nativeChainId);
const bridgeId = solidityKeccak256(["uint256", "bytes"], [chainIdBuffer, nativeTokenAddress]);
return bridgeId;
}
export function hashExternalCallBytes(data) {
if (data === undefined || (data === null || data === void 0 ? void 0 : data.length) === 0) {
// precomputed "empty" hash
return Buffer.from([
197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192,
229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112,
]);
}
return hexToBuffer(solidityKeccak256(["bytes"], [data ? data : Buffer.from([])]), 32);
}
function isSendHashedFlagSet(packedFlags) {
const SEND_HASHED_DATA_FLAG_BIT_NUMBER = BigInt(3);
const result = (packedFlags >> SEND_HASHED_DATA_FLAG_BIT_NUMBER) & BigInt(1);
return result === BigInt(1);
}
function getShortcutFromAutoParams(params) {
var _a, _b, _c;
const shortcut = (_a = params.autoParams) === null || _a === void 0 ? void 0 : _a.shortcut;
if (shortcut) {
return isBuffer(shortcut) ? shortcut : hexToBuffer(shortcut);
}
else {
const flags = BigInt(new BN(((_b = params.autoParams) === null || _b === void 0 ? void 0 : _b.flags) || 0).toNumber());
const data = (_c = params.autoParams) === null || _c === void 0 ? void 0 : _c.data;
if (!data)
return hashExternalCallBytes(data);
if (isSendHashedFlagSet(flags)) {
const result = isBuffer(data) ? data : hexToBuffer(data);
if (result.length !== 32) {
throw new Error(`Incorrect autoParams.data length for SEND_HASHED_DATA_FLAG`);
}
return result;
}
return hashExternalCallBytes(data);
}
}
/**
* Hashes submission for provided data
* @param params data to hash
* @returns submissionId from provided params
*/
export function hashSubmissionIdRaw(params) {
var _a, _b;
let packParams = [
"uint256", // submission prefix
"bytes32", // bridge_id
"uint256", // source_chain_id
"uint256", // target_chain_id
"uint256", // amount
"bytes", // receiver
"uint256", // nonce
];
const receiver = isBuffer(params.receiver)
? params.receiver
: typeof params.receiver === "string"
? params.receiver.startsWith("0x")
? hexToBuffer(params.receiver)
: new PublicKey(params.receiver).toBuffer()
: new PublicKey(params.receiver).toBuffer();
let packData = [
SUBMISSION_PREFIX,
params.debridgeId, // bridge_id
normalizeChainId(params.sourceChainId), // source_chain_id
normalizeChainId(params.targetChainId), // target_chain_id
new BN(params.amount).toArray("be", 32), // amount
receiver, // receiver
params.nonce, // nonce
];
if (params === null || params === void 0 ? void 0 : params.autoParams) {
packParams = packParams.concat([
"uint256", // execution fee
"uint256", // flag
"bytes32", // fallback hash
"uint256", // ext call data hash
"uint256", // native sender hash
]);
const shortcut = getShortcutFromAutoParams(params);
const fallback = params.autoParams.fallbackAddress.startsWith("0x")
? hexToBuffer(params.autoParams.fallbackAddress)
: new PublicKey(params.autoParams.fallbackAddress).toBuffer();
packData = packData.concat([
new BN(((_a = params === null || params === void 0 ? void 0 : params.autoParams) === null || _a === void 0 ? void 0 : _a.executionFee) || 0).toArray("be", 32),
new BN(((_b = params.autoParams) === null || _b === void 0 ? void 0 : _b.flags) || 0).toArray("be", 32),
hashExternalCallBytes(fallback),
shortcut,
hashExternalCallBytes(params.autoParams.nativeSender),
]);
}
const submissionIdHash = solidityKeccak256(packParams, packData);
return submissionIdHash;
}
//# sourceMappingURL=crypto.js.map