@desig/web3
Version:
Desig: The Blockchain-Agnostic Multisig Solution
178 lines • 10.4 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transaction = void 0;
const core_1 = require("@desig/core");
const connection_1 = require("../connection");
const utils_1 = require("@noble/hashes/utils");
const sha3_1 = require("@noble/hashes/sha3");
const bs58_1 = require("bs58");
const types_1 = require("../types");
const supported_chains_1 = require("@desig/supported-chains");
const transaction_parser_1 = require("./transaction.parser");
class Transaction extends connection_1.Connection {
constructor(cluster, privkey, keypair) {
super(cluster, (0, bs58_1.decode)(privkey), keypair);
this.watch = (callback) => {
const multisigId = (0, bs58_1.encode)(this.keypair.masterkey);
const unwatch = this.on(connection_1.EventStreaming.signature, multisigId, callback);
return unwatch;
};
this.getTransactions = ({ approved, size = 10, after, } = {}) => __awaiter(this, void 0, void 0, function* () {
const params = {
multisigId: (0, bs58_1.encode)(this.keypair.masterkey),
size,
after,
};
if (typeof approved === 'boolean')
params.approved = approved;
const { data } = yield this.connection.get('/transaction', {
params,
});
return data;
});
this.getTransaction = (transactionId) => __awaiter(this, void 0, void 0, function* () {
const { data } = yield this.connection.get(`/transaction/${transactionId}`);
return data;
});
this.getSignature = (signatureId) => __awaiter(this, void 0, void 0, function* () {
const { data } = yield this.connection.get(`/signature/${signatureId}`);
return data;
});
this.initializeTransaction = ({ type, params, ttl, }) => __awaiter(this, void 0, void 0, function* () {
const payload = {
multisigId: (0, bs58_1.encode)(this.keypair.masterkey),
type,
params,
};
if (ttl)
payload.ttl = ttl;
const Authorization = yield this.getAuthorization(payload);
const { data } = yield this.connection.post('/transaction', payload, { headers: { Authorization } });
return data;
});
this.signTransaction = (transactionId) => __awaiter(this, void 0, void 0, function* () {
const txParser = new transaction_parser_1.TransactionParser();
const elgamal = new core_1.ElGamal();
const { msg, raw, signatures } = yield this.getTransaction(transactionId);
const { pullrequest } = signatures.find(({ signer: { id } }) => id === this.index);
let sig = this.sign((0, bs58_1.decode)(this.index), (0, bs58_1.decode)(msg));
const tx = (0, bs58_1.decode)(raw);
const { txType } = (yield txParser.verify(tx)) || {};
if (txType === types_1.TransactionType.nExtension) {
const r = elgamal.decrypt((0, bs58_1.decode)(pullrequest).subarray(0, 64), this.privkey);
const z = this.sss.ff.add(this.keypair.share, r);
sig = (0, utils_1.concatBytes)(sig, z);
}
else if (txType === types_1.TransactionType.nReduction) {
}
else if (txType === types_1.TransactionType.tExtension) {
}
else if (txType === types_1.TransactionType.tReduction) {
const r = elgamal.decrypt((0, bs58_1.decode)(pullrequest).subarray(0, 64), this.privkey);
const z = this.sss.ff.add(this.keypair.share, r);
sig = (0, utils_1.concatBytes)(sig, z);
}
else
throw new Error('Invalid transaction type');
const signatureId = Transaction.deriveSignatureId(transactionId, this.index);
const payload = { signature: (0, bs58_1.encode)(sig) };
const Authorization = yield this.getAuthorization(payload);
const { data } = yield this.connection.patch(`/signature/${signatureId}`, payload, { headers: { Authorization } });
return data;
});
this.execTransaction = (transactionId) => __awaiter(this, void 0, void 0, function* () {
const { data } = yield this.connection.patch(`/transaction/${transactionId}`);
return data;
});
this.syncTransaction = () => __awaiter(this, void 0, void 0, function* () {
const txParser = new transaction_parser_1.TransactionParser();
const extendedElgamal = new core_1.ExtendedElGamal();
const elgamal = new core_1.ElGamal();
const ff = this.sss.ff;
const txs = yield this.getTransactions({ approved: true });
const currentGid = (0, bs58_1.encode)(this.keypair.id);
let currentPos = -1;
for (let i = 0; i < txs.length; i++) {
const { raw } = txs[i];
const { refgid } = yield txParser.verify((0, bs58_1.decode)(raw));
if ((0, bs58_1.encode)(refgid) === currentGid) {
currentPos = i;
break;
}
}
if (currentPos < 0)
throw new Error('Corrupted chain data.');
const waitingTxs = txs.slice(0, currentPos + 1);
while (waitingTxs.length) {
const { id: transactionId, raw } = waitingTxs.pop();
const { signatures } = yield this.getTransaction(transactionId);
const tx = (0, bs58_1.decode)(raw);
const { txType, refgid, t, n } = yield txParser.verify(tx);
const _t = ff.decode(ff.numberToRedBN(t), 8);
const _n = ff.decode(ff.numberToRedBN(n), 8);
const { pullrequest } = signatures.find(({ signer: { id } }) => id === this.index) || { pullrequest: (0, bs58_1.encode)(tx.subarray(72)) };
if (txType === types_1.TransactionType.nExtension) {
const zero = elgamal.decrypt((0, bs58_1.decode)(pullrequest).subarray(64, 128), this.privkey);
this.keypair.proactivate((0, utils_1.concatBytes)(this.keypair.index, _t, _n, (0, bs58_1.decode)(transactionId), zero));
}
else if (txType === types_1.TransactionType.nReduction) {
const zero = elgamal.decrypt((0, bs58_1.decode)(pullrequest), this.privkey);
this.keypair.proactivate((0, utils_1.concatBytes)(this.keypair.index, _t, _n, (0, bs58_1.decode)(transactionId), zero));
}
else if (txType === types_1.TransactionType.tExtension) {
const zero = elgamal.decrypt((0, bs58_1.decode)(pullrequest), this.privkey);
this.keypair.proactivate((0, utils_1.concatBytes)(this.keypair.index, _t, _n, (0, bs58_1.decode)(transactionId), zero));
}
else if (txType === types_1.TransactionType.tReduction) {
const zero = elgamal.decrypt((0, bs58_1.decode)(pullrequest).subarray(64, 128), this.privkey);
const shares = signatures
.filter(({ signature }) => !!signature)
.map(({ signature, signer: { id } }) => [
(0, bs58_1.decode)(id),
(0, bs58_1.decode)(signature),
])
.map(([id, signature]) => {
const commitment = signature.subarray(64);
return (0, utils_1.concatBytes)(id, ff.decode(ff.numberToRedBN(t).add(this.sss.ff.ONE), 8), _n, refgid, commitment);
});
const z = this.sss.ff.neg(this.sss.ff.mul(this.sss.ft1(shares), this.sss.ff.pow(this.keypair.index, t)));
this.keypair.proactivate((0, utils_1.concatBytes)(this.keypair.index, _t, _n, (0, bs58_1.decode)(transactionId), z));
this.keypair.proactivate((0, utils_1.concatBytes)(this.keypair.index, _t, _n, (0, bs58_1.decode)(transactionId), zero));
}
else
throw new Error('Unsupported Desig transaction.');
}
const encryptedShare = (0, bs58_1.encode)(extendedElgamal.encrypt(new TextEncoder().encode(this.keypair.getSecretKey()), (0, bs58_1.decode)(this.owner)));
const payload = { activated: true, encryptedShare };
const Authorization = yield this.getAuthorization(payload);
const { data } = yield this.connection.patch(`/signer/${this.index}`, payload, { headers: { Authorization } });
return data;
});
this.sss = (() => {
switch (this.keypair.curve) {
case supported_chains_1.Curve.ed25519:
return new core_1.SecretSharing(core_1.EdCurve.ff);
case supported_chains_1.Curve.secp256k1:
return new core_1.SecretSharing(core_1.ECCurve.ff);
default:
throw new Error('Unsupported elliptic curve.');
}
})();
}
static deriveSignatureId(transactionId, signerId) {
const seed = (0, utils_1.concatBytes)((0, bs58_1.decode)(transactionId), (0, bs58_1.decode)(signerId));
return (0, bs58_1.encode)((0, sha3_1.keccak_256)(seed));
}
}
exports.Transaction = Transaction;
Transaction.deriveTransactionId = (msg) => (0, bs58_1.encode)((0, bs58_1.decode)(msg).subarray(0, 8));
//# sourceMappingURL=index.js.map