@debridge-finance/solana-utils
Version:
Common utils package to power communication with Solana contracts at deBridge
169 lines • 5.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.solidityPack = solidityPack;
const tslib_1 = require("tslib");
const bn_js_1 = tslib_1.__importDefault(require("bn.js"));
const helpers_1 = require("./helpers");
/**
* All functions are copied from ethers. This is optimization to reduce dependencies
*/
function concat(items) {
const objects = items.map((item) => arrayify(item));
const length = objects.reduce((accum, item) => accum + item.length, 0);
const result = new Uint8Array(length);
objects.reduce((offset, object) => {
result.set(object, offset);
return offset + object.length;
}, 0);
return result;
}
function arrayify(value) {
if (typeof value === "number") {
const numValue = value;
const result = [];
while (value) {
result.unshift(numValue & 0xff);
value = parseInt(String(numValue / 256));
}
if (result.length === 0) {
result.push(0);
}
return new Uint8Array(result);
}
if (bn_js_1.default.isBN(value)) {
value = `0x${value.toString("hex")}`;
}
if (typeof value === "string" && value.startsWith("0x")) {
return (0, helpers_1.hexToBuffer)(value);
}
if (Array.isArray(value) || ArrayBuffer.isView(value)) {
return new Uint8Array(value);
}
throw new Error(`unknown value: ${value}`);
}
// http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
function toUtf8Bytes(str) {
let result = [];
for (let i = 0; i < str.length; i++) {
const c = str.charCodeAt(i);
if (c < 0x80) {
result.push(c);
}
else if (c < 0x800) {
result.push((c >> 6) | 0xc0);
result.push((c & 0x3f) | 0x80);
}
else if ((c & 0xfc00) == 0xd800) {
i++;
const c2 = str.charCodeAt(i);
if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) {
throw new Error("invalid utf-8 string");
}
// Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
result.push((pair >> 18) | 0xf0);
result.push(((pair >> 12) & 0x3f) | 0x80);
result.push(((pair >> 6) & 0x3f) | 0x80);
result.push((pair & 0x3f) | 0x80);
}
else {
result.push((c >> 12) | 0xe0);
result.push(((c >> 6) & 0x3f) | 0x80);
result.push((c & 0x3f) | 0x80);
}
}
return arrayify(result);
}
const zeroPad = (value, length) => {
const bufValue = arrayify(value);
if (bufValue.length > length) {
throw new Error("value out of range");
}
const result = new Uint8Array(length);
result.set(bufValue, length - bufValue.length);
return result;
};
const isHexString = (data) => typeof data === "string" && data.startsWith("0x");
const _pack = (type, value, isArray) => {
const regexBytes = new RegExp("^bytes([0-9]+)$");
const regexNumber = new RegExp("^(u?int)([0-9]*)$");
const regexArray = new RegExp("^(.*)\\[([0-9]*)\\]$");
const Zeros = "0000000000000000000000000000000000000000000000000000000000000000";
switch (type) {
case "address":
if (isArray) {
return zeroPad(value, 32);
}
return arrayify(value);
case "string":
return toUtf8Bytes(value);
case "bytes":
return arrayify(value);
case "bool":
value = value ? "0x01" : "0x00";
if (isArray) {
return zeroPad(value, 32);
}
return arrayify(value);
}
let match = type.match(regexNumber);
if (match) {
//let signed = (match[1] === "int")
let size = parseInt(match[2] || "256");
if ((match[2] && String(size) !== match[2]) ||
size % 8 !== 0 ||
size === 0 ||
size > 256) {
throw new Error("invalid number type");
}
if (isArray) {
size = 256;
}
if (isHexString(value)) {
value = new bn_js_1.default(value.slice(2), "hex").toTwos(size);
}
else {
value = new bn_js_1.default(value).toTwos(size);
}
return zeroPad(value, size / 8);
}
match = type.match(regexBytes);
if (match) {
const size = parseInt(match[1]);
if (String(size) !== match[1] || size === 0 || size > 32) {
throw new Error("invalid bytes type");
}
if (arrayify(value).byteLength !== size) {
throw new Error(`invalid value for ${type}`);
}
if (isArray) {
return arrayify((value + Zeros).substring(0, 66));
}
return value;
}
match = type.match(regexArray);
if (match && Array.isArray(value)) {
const baseType = match[1];
const count = parseInt(match[2] || String(value.length));
if (count != value.length) {
throw new Error(`invalid array length for ${type}`);
}
const result = [];
value.forEach(function (value) {
result.push(_pack(baseType, value, true));
});
return concat(result);
}
throw new Error("invalid type");
};
function solidityPack(types, values) {
if (types.length != values.length) {
throw new Error("types and values length mismatch");
}
const tight = [];
types.forEach((type, index) => {
tight.push(_pack(type, values[index]));
});
return concat(tight);
}
//# sourceMappingURL=solidityPack.js.map