Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/constants/internalPubkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.internalPubkey = void 0;
// internalPubkey denotes an unspendable internal public key to be used for the taproot output
const key = "0264173d3a9fb10d58cb5553332f0fa2b971809d1a8626ca7cb6eebb66eb4cb9ec";
// NUMS point: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs
const key = "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
exports.internalPubkey = Buffer.from(key, "hex").subarray(1, 33); // Do a subarray(1, 33) to get the public coordinate
16 changes: 15 additions & 1 deletion lib/covenantV1/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ Object.defineProperty(exports, "initBTCCurve", { enumerable: true, get: function
const bridge_script_1 = require("./bridge.script");
Object.defineProperty(exports, "buildDepositScript", { enumerable: true, get: function () { return bridge_script_1.buildDepositScript; } });
const fee_1 = require("../utils/fee");
const scriptUtils_1 = require("../utils/scriptUtils");
// https://bips.xyz/370
const BTC_DUST_SAT = 546;
function depositTransaction(scripts, amount, changeAddress, inputUTXOs, network, feeRate) {
if (amount <= 0 || feeRate <= 0) {
throw new Error("Amount and fee rate must be bigger than 0");
}
if (feeRate < scriptUtils_1.minBtc) {
throw new Error(`fee rate cannot be less than or equal to ${scriptUtils_1.minBtc}`);
}
const psbt = new bitcoinjs_lib_1.Psbt({ network });
const p2wsh = bitcoinjs_lib_1.payments.p2wsh({
redeem: { output: scripts.depositScript, network },
Expand Down Expand Up @@ -51,11 +55,17 @@ function sendTransaction(scripts, depositTransaction, sendAddress, minimumFee, n
if (minimumFee <= 0) {
throw new Error("Minimum fee must be bigger than 0");
}
if (minimumFee < scriptUtils_1.minBtc) {
throw new Error(`Minimum fee cannot be less than or equal to ${scriptUtils_1.minBtc}`);
}
// Ensure that the minimum fee does not exceed the output value
const outputValue = depositTransaction.outs[outputIndex].value;
if (minimumFee >= outputValue) {
throw new Error("Minimum fee must be less than the output value");
}
if ((0, scriptUtils_1.hasOpReturnOutput)(depositTransaction.outs[outputIndex])) {
throw new Error("OP RETURN cannot exist in the output");
}
const psbt = new bitcoinjs_lib_1.Psbt({ network });
psbt.addInput({
hash: depositTransaction.getHash(),
Expand All @@ -66,9 +76,13 @@ function sendTransaction(scripts, depositTransaction, sendAddress, minimumFee, n
},
witnessScript: scripts.depositScript // This is typically the same as the script used for depositing if P2WSH was used
});
const value = outputValue - minimumFee;
if (value < scriptUtils_1.minBtc) {
throw new Error(`The output value cannot be less than ${scriptUtils_1.minBtc}`);
}
psbt.addOutput({
address: sendAddress,
value: outputValue - minimumFee // Subtract the minimum fee from the output value
value // Subtract the minimum fee from the output value
});
return { psbt };
}
Expand Down
14 changes: 7 additions & 7 deletions lib/slashable/locking/script.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LockingScripts } from "../../types/LockingScripts";
export declare const PK_LENGTH = 32;
export declare class LockingScriptData {
#private;
constructor(lockrKey: Buffer, covenantKeys: Buffer[], covenantThreshold: number, lockingTimelock: number, unbondingTimelock: number, magicBytes: Buffer);
constructor(lockerKey: Buffer, operatorKeys: Buffer[], covenantKeys: Buffer[], covenantThreshold: number, lockingTimelock: number, unbondingTimelock: number, magicBytes: Buffer);
/**
* Validates the locking script.
* @return {boolean} Returns true if the locking script is valid, otherwise false.
Expand All @@ -19,7 +19,7 @@ export declare class LockingScriptData {
* Builds the locking timelock script.
* Only holder of private key for given pubKey can spend after relative lock time
* Creates the timelock script in the form:
* <lockrPubKey>
* <lockerPubKey>
* OP_CHECKSIGVERIFY
* <lockingTimeBlocks>
* OP_CHECKSEQUENCEVERIFY
Expand All @@ -29,7 +29,7 @@ export declare class LockingScriptData {
/**
* Builds the unbonding timelock script.
* Creates the unbonding timelock script in the form:
* <lockrPubKey>
* <lockerPubKey>
* OP_CHECKSIGVERIFY
* <unbondingTimeBlocks>
* OP_CHECKSEQUENCEVERIFY
Expand All @@ -38,19 +38,19 @@ export declare class LockingScriptData {
buildUnbondingTimelockScript(): Buffer;
/**
* Builds the unbonding script in the form:
* buildSingleKeyScript(lockrPk, true) ||
* buildSingleKeyScript(lockerPk, true) ||
* buildMultiKeyScript(covenantPks, covenantThreshold, false)
* || means combining the scripts
* @return {Buffer} The unbonding script.
*/
buildUnbondingScript(): Buffer;
/**
* Builds the slashing script for locking in the form:
* buildSingleKeyScript(lockrPk, true) ||
* buildSingleKeyScript(lockerPk, true) ||
* buildMultiKeyScript(covenantPks, covenantThreshold, false)
* || means combining the scripts
* The slashing script is a combination of single-key and multi-key scripts.
* The single-key script is used for lockr key verification.
* The single-key script is used for locker key verification.
* The multi-key script is used for covenant key verification.
* @return {Buffer} The slashing script as a Buffer.
*/
Expand All @@ -59,7 +59,7 @@ export declare class LockingScriptData {
* Builds a data script for locking in the form:
* OP_RETURN || <serializedLockingData>
* where serializedLockingData is the concatenation of:
* MagicBytes || Version || LockrPublicKey || LockingTimeLock
* MagicBytes || Version || lockerPublicKey || LockingTimeLock
* @return {Buffer} The compiled provably note script.
*/
buildProvablyNoteScript(): Buffer;
Expand Down
76 changes: 53 additions & 23 deletions lib/slashable/locking/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _LockingScriptData_instances, _LockingScriptData_lockrKey, _LockingScriptData_covenantKeys, _LockingScriptData_covenantThreshold, _LockingScriptData_lockingTimeLock, _LockingScriptData_unbondingTimeLock, _LockingScriptData_magicBytes, _LockingScriptData_buildSingleKeyScript, _LockingScriptData_buildMultiKeyScript;
var _LockingScriptData_instances, _LockingScriptData_lockerKey, _LockingScriptData_operatorKeys, _LockingScriptData_covenantKeys, _LockingScriptData_covenantThreshold, _LockingScriptData_lockingTimeLock, _LockingScriptData_unbondingTimeLock, _LockingScriptData_magicBytes, _LockingScriptData_buildSingleKeyScript, _LockingScriptData_buildMultiKeyScript;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LockingScriptData = exports.PK_LENGTH = void 0;
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
Expand All @@ -20,10 +20,11 @@ exports.PK_LENGTH = 32;
// and exposes methods for converting it into useful formats
class LockingScriptData {
constructor(
// The `lockrKey` is the public key of the lockr without the coordinate bytes.
lockrKey,
// A list of the public keys without the coordinate bytes corresponding to
// the covenant emulators.
// The `lockerKey` is the public key of the locker without the coordinate bytes.
lockerKey,
// A list of the public keys indicating the sequencer nodes
operatorKeys,
// A list of the public keys indicating the committee members.
// This is a parameter of the goat system and should be retrieved from there.
covenantKeys,
// The number of covenant emulator signatures required for a transaction
Expand All @@ -40,22 +41,25 @@ class LockingScriptData {
// through the data return script
magicBytes) {
_LockingScriptData_instances.add(this);
_LockingScriptData_lockrKey.set(this, void 0);
_LockingScriptData_lockerKey.set(this, void 0);
_LockingScriptData_operatorKeys.set(this, void 0);
_LockingScriptData_covenantKeys.set(this, void 0);
_LockingScriptData_covenantThreshold.set(this, void 0);
_LockingScriptData_lockingTimeLock.set(this, void 0);
_LockingScriptData_unbondingTimeLock.set(this, void 0);
_LockingScriptData_magicBytes.set(this, void 0);
// Check that required input values are not missing when creating an instance of the LockingScriptData class
if (!lockrKey ||
if (!lockerKey ||
!operatorKeys ||
!covenantKeys ||
!covenantThreshold ||
!lockingTimelock ||
!unbondingTimelock ||
!magicBytes) {
throw new Error("Missing required input values");
}
__classPrivateFieldSet(this, _LockingScriptData_lockrKey, lockrKey, "f");
__classPrivateFieldSet(this, _LockingScriptData_lockerKey, lockerKey, "f");
__classPrivateFieldSet(this, _LockingScriptData_operatorKeys, operatorKeys, "f");
__classPrivateFieldSet(this, _LockingScriptData_covenantKeys, covenantKeys, "f");
__classPrivateFieldSet(this, _LockingScriptData_covenantThreshold, covenantThreshold, "f");
__classPrivateFieldSet(this, _LockingScriptData_lockingTimeLock, lockingTimelock, "f");
Expand All @@ -71,16 +75,40 @@ class LockingScriptData {
* @return {boolean} Returns true if the locking script is valid, otherwise false.
*/
validate() {
// check that lockr key is the correct length
if (__classPrivateFieldGet(this, _LockingScriptData_lockrKey, "f").length != exports.PK_LENGTH) {
// check that locker key is the correct length
if (__classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f").length != exports.PK_LENGTH) {
return false;
}
// check that operator keys are the correct length
if (__classPrivateFieldGet(this, _LockingScriptData_operatorKeys, "f").some((operatorKey) => operatorKey.length != exports.PK_LENGTH)) {
return false;
}
// check that covenant keys are the correct length
if (__classPrivateFieldGet(this, _LockingScriptData_covenantKeys, "f").some((covenantKey) => covenantKey.length != exports.PK_LENGTH)) {
return false;
}
// check that maximum value for locking time is not greater than uint16
if (__classPrivateFieldGet(this, _LockingScriptData_lockingTimeLock, "f") > 65535) {
// Check whether we have any duplicate keys
const allPks = [
__classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f"),
...__classPrivateFieldGet(this, _LockingScriptData_operatorKeys, "f"),
...__classPrivateFieldGet(this, _LockingScriptData_covenantKeys, "f")
];
const allPksSet = new Set(allPks);
if (allPks.length !== allPksSet.size) {
return false;
}
// check that the threshold is above 0 and less than or equal to
// the size of the covenant emulators set
if (__classPrivateFieldGet(this, _LockingScriptData_covenantThreshold, "f") == 0 ||
__classPrivateFieldGet(this, _LockingScriptData_covenantThreshold, "f") > __classPrivateFieldGet(this, _LockingScriptData_covenantKeys, "f").length) {
return false;
}
// check that maximum value for staking time is not greater than uint16 and above 0
if (__classPrivateFieldGet(this, _LockingScriptData_lockingTimeLock, "f") == 0 || __classPrivateFieldGet(this, _LockingScriptData_lockingTimeLock, "f") > 65535) {
return false;
}
// check that maximum value for unbonding time is not greater than uint16 and above 0
if (__classPrivateFieldGet(this, _LockingScriptData_unbondingTimeLock, "f") == 0 || __classPrivateFieldGet(this, _LockingScriptData_unbondingTimeLock, "f") > 65535) {
return false;
}
return true;
Expand All @@ -92,7 +120,7 @@ class LockingScriptData {
*/
buildTimelockScript(timelock) {
return bitcoinjs_lib_1.script.compile([
__classPrivateFieldGet(this, _LockingScriptData_lockrKey, "f"),
__classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f"),
bitcoinjs_lib_1.opcodes.OP_CHECKSIGVERIFY,
bitcoinjs_lib_1.script.number.encode(timelock),
bitcoinjs_lib_1.opcodes.OP_CHECKSEQUENCEVERIFY
Expand All @@ -102,7 +130,7 @@ class LockingScriptData {
* Builds the locking timelock script.
* Only holder of private key for given pubKey can spend after relative lock time
* Creates the timelock script in the form:
* <lockrPubKey>
* <lockerPubKey>
* OP_CHECKSIGVERIFY
* <lockingTimeBlocks>
* OP_CHECKSEQUENCEVERIFY
Expand All @@ -114,7 +142,7 @@ class LockingScriptData {
/**
* Builds the unbonding timelock script.
* Creates the unbonding timelock script in the form:
* <lockrPubKey>
* <lockerPubKey>
* OP_CHECKSIGVERIFY
* <unbondingTimeBlocks>
* OP_CHECKSEQUENCEVERIFY
Expand All @@ -125,30 +153,31 @@ class LockingScriptData {
}
/**
* Builds the unbonding script in the form:
* buildSingleKeyScript(lockrPk, true) ||
* buildSingleKeyScript(lockerPk, true) ||
* buildMultiKeyScript(covenantPks, covenantThreshold, false)
* || means combining the scripts
* @return {Buffer} The unbonding script.
*/
buildUnbondingScript() {
return Buffer.concat([
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildSingleKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_lockrKey, "f"), true),
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildSingleKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f"), true),
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildMultiKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_covenantKeys, "f"), __classPrivateFieldGet(this, _LockingScriptData_covenantThreshold, "f"), false)
]);
}
/**
* Builds the slashing script for locking in the form:
* buildSingleKeyScript(lockrPk, true) ||
* buildSingleKeyScript(lockerPk, true) ||
* buildMultiKeyScript(covenantPks, covenantThreshold, false)
* || means combining the scripts
* The slashing script is a combination of single-key and multi-key scripts.
* The single-key script is used for lockr key verification.
* The single-key script is used for locker key verification.
* The multi-key script is used for covenant key verification.
* @return {Buffer} The slashing script as a Buffer.
*/
buildSlashingScript() {
return Buffer.concat([
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildSingleKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_lockrKey, "f"), true),
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildSingleKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f"), true),
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildMultiKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_operatorKeys, "f"), 1, true),
__classPrivateFieldGet(this, _LockingScriptData_instances, "m", _LockingScriptData_buildMultiKeyScript).call(this, __classPrivateFieldGet(this, _LockingScriptData_covenantKeys, "f"), __classPrivateFieldGet(this, _LockingScriptData_covenantThreshold, "f"),
// No need to add verify since covenants are at the end of the script
false)
Expand All @@ -158,7 +187,7 @@ class LockingScriptData {
* Builds a data script for locking in the form:
* OP_RETURN || <serializedLockingData>
* where serializedLockingData is the concatenation of:
* MagicBytes || Version || LockrPublicKey || LockingTimeLock
* MagicBytes || Version || lockerPublicKey || LockingTimeLock
* @return {Buffer} The compiled provably note script.
*/
buildProvablyNoteScript() {
Expand All @@ -172,7 +201,8 @@ class LockingScriptData {
const serializedLockingData = Buffer.concat([
__classPrivateFieldGet(this, _LockingScriptData_magicBytes, "f"),
version,
__classPrivateFieldGet(this, _LockingScriptData_lockrKey, "f"),
__classPrivateFieldGet(this, _LockingScriptData_lockerKey, "f"),
__classPrivateFieldGet(this, _LockingScriptData_operatorKeys, "f")[0],
lockingTimeLock
]);
return bitcoinjs_lib_1.script.compile([bitcoinjs_lib_1.opcodes.OP_RETURN, serializedLockingData]);
Expand All @@ -192,7 +222,7 @@ class LockingScriptData {
}
}
exports.LockingScriptData = LockingScriptData;
_LockingScriptData_lockrKey = new WeakMap(), _LockingScriptData_covenantKeys = new WeakMap(), _LockingScriptData_covenantThreshold = new WeakMap(), _LockingScriptData_lockingTimeLock = new WeakMap(), _LockingScriptData_unbondingTimeLock = new WeakMap(), _LockingScriptData_magicBytes = new WeakMap(), _LockingScriptData_instances = new WeakSet(), _LockingScriptData_buildSingleKeyScript = function _LockingScriptData_buildSingleKeyScript(pk, withVerify) {
_LockingScriptData_lockerKey = new WeakMap(), _LockingScriptData_operatorKeys = new WeakMap(), _LockingScriptData_covenantKeys = new WeakMap(), _LockingScriptData_covenantThreshold = new WeakMap(), _LockingScriptData_lockingTimeLock = new WeakMap(), _LockingScriptData_unbondingTimeLock = new WeakMap(), _LockingScriptData_magicBytes = new WeakMap(), _LockingScriptData_instances = new WeakSet(), _LockingScriptData_buildSingleKeyScript = function _LockingScriptData_buildSingleKeyScript(pk, withVerify) {
// Check public key length
if (pk.length != exports.PK_LENGTH) {
throw new Error("Invalid key length");
Expand Down
2 changes: 1 addition & 1 deletion lib/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

Loading