UNPKG

@node-dlc/messaging

Version:
315 lines (271 loc) 10.8 kB
import { expect } from 'chai'; import { CetAdaptorSignatures } from '../../lib/messages/CetAdaptorSignatures'; import { DlcAccept, DlcAcceptContainer } from '../../lib/messages/DlcAccept'; import { FundingInput } from '../../lib/messages/FundingInput'; import { MessageType } from '../../lib/MessageType'; describe('DlcAccept', () => { let instance: DlcAccept; const temporaryContractId = Buffer.from( '960fb5f7960382ac7e76f3e24eb6b00059b1e68632a946843c22e1f65fdf216a', 'hex', ); const fundingPubkey = Buffer.from( '026d8bec9093f96ccc42de166cb9a6c576c95fc24ee16b10e87c3baaa4e49684d9', 'hex', ); const payoutSpk = Buffer.from( '001436054fa379f7564b5e458371db643666365c8fb3', 'hex', ); const fundingInput = Buffer.from( 'fda714' + // type funding_input_v0 '3f' + // length '000000000000dae8' + // input_serial_id '0029' + // prevtx_len '02000000000100c2eb0b000000001600149ea3bf2d6eb9c2ffa35e36f41e117403ed7fafe900000000' + // prevtx '00000000' + // prevtx_vout 'ffffffff' + // sequence '006b' + // max_witness_len '0000', // redeem_script_len 'hex', ); const changeSpk = Buffer.from( '0014074c82dbe058212905bacc61814456b7415012ed', 'hex', ); const refundSignature = Buffer.alloc(64, 0x01); // Simple test signature beforeEach(() => { instance = new DlcAccept(); instance.protocolVersion = 1; // Set protocol version instance.temporaryContractId = temporaryContractId; instance.acceptCollateral = BigInt(100000000); instance.fundingPubkey = fundingPubkey; instance.payoutSpk = payoutSpk; instance.payoutSerialId = BigInt(1594186); instance.fundingInputs = [FundingInput.deserialize(fundingInput)]; instance.changeSpk = changeSpk; instance.changeSerialId = BigInt(885015); // Create test CET adaptor signatures instance.cetAdaptorSignatures = new CetAdaptorSignatures(); instance.cetAdaptorSignatures.sigs = [ { encryptedSig: Buffer.alloc(65), dleqProof: Buffer.alloc(97), }, ]; instance.refundSignature = refundSignature; }); describe('deserialize', () => { it('has correct type', () => { expect(DlcAccept.deserialize(instance.serialize()).type).to.equal( instance.type, ); }); it('deserializes without cets', () => { // Set parseCets to false const dlcAccept = DlcAccept.deserialize(instance.serialize(), false); expect(dlcAccept.cetAdaptorSignatures.sigs.length).to.be.equal(0); }); }); describe('DlcAccept', () => { describe('serialize', () => { it('serializes', () => { // Test round-trip consistency instead of exact hex match const serialized = instance.serialize(); const deserialized = DlcAccept.deserialize(serialized); expect(deserialized.temporaryContractId).to.deep.equal( instance.temporaryContractId, ); expect(deserialized.acceptCollateral).to.equal( instance.acceptCollateral, ); expect(deserialized.fundingPubkey).to.deep.equal( instance.fundingPubkey, ); expect(deserialized.payoutSpk).to.deep.equal(instance.payoutSpk); expect(deserialized.payoutSerialId).to.equal(instance.payoutSerialId); expect(deserialized.changeSpk).to.deep.equal(instance.changeSpk); expect(deserialized.changeSerialId).to.equal(instance.changeSerialId); expect(deserialized.refundSignature).to.deep.equal( instance.refundSignature, ); }); it('serializes a dlcAccept without cets', () => { const _dlcAcceptWithoutSigs = DlcAccept.deserialize( instance.serialize(), false, ); const dlcAcceptWithoutSigs = DlcAccept.deserialize( _dlcAcceptWithoutSigs.serialize(), true, ); expect( dlcAcceptWithoutSigs.cetAdaptorSignatures.sigs.length, ).to.be.equal(0); }); }); describe('deserialize', () => { it('deserializes', () => { // Test round-trip consistency const serialized = instance.serialize(); const deserialized = DlcAccept.deserialize(serialized); expect(deserialized.temporaryContractId).to.deep.equal( temporaryContractId, ); expect(Number(deserialized.acceptCollateral)).to.equal(100000000); expect(deserialized.fundingPubkey).to.deep.equal(fundingPubkey); expect(deserialized.payoutSpk).to.deep.equal(payoutSpk); expect(Number(deserialized.payoutSerialId)).to.equal(1594186); expect(deserialized.changeSpk).to.deep.equal(changeSpk); expect(Number(deserialized.changeSerialId)).to.equal(885015); expect(deserialized.refundSignature).to.deep.equal(refundSignature); }); it('has correct type', () => { expect(DlcAccept.deserialize(instance.serialize()).type).to.equal( MessageType.DlcAccept, ); }); }); describe('toJSON', () => { it('convert to JSON', async () => { const json = instance.toJSON(); // Basic structure validation - detailed field testing is done in cross-language tests expect(json.temporaryContractId).to.be.a('string'); expect(json.fundingPubkey).to.be.a('string'); expect(json.payoutSpk).to.be.a('string'); expect(json.changeSpk).to.be.a('string'); expect(json.refundSignature).to.be.a('string'); expect(json.acceptCollateral).to.be.a('number'); }); }); describe('withoutSigs', () => { it('does not contain sigs', () => { const withoutSigs = DlcAccept.deserialize( instance.serialize(), ).withoutSigs(); expect(withoutSigs['cetAdaptorSignatures']).to.not.exist; }); }); describe('validate', () => { it('should throw if payout_spk is invalid', () => { instance.payoutSpk = Buffer.from('fff', 'hex'); expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if change_spk is invalid', () => { instance.changeSpk = Buffer.from('fff', 'hex'); expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if fundingpubkey is not a valid pubkey', () => { instance.fundingPubkey = Buffer.from( '00f003aa11f2a97b6be755a86b9fd798a7451c670196a5245b7bae971306b7c87e', 'hex', ); expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if fundingpubkey is not in compressed secp256k1 format', () => { instance.fundingPubkey = Buffer.from( '045162991c7299223973cabc99ef5087d7bab2dafe61f78e5388b2f9492f7978123f51fd05ef0693790c0b2d4f30848363a3f3fbcf2bd53a05ba0fd5bb708c3184', 'hex', ); expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if inputSerialIds arent unique', () => { instance.fundingInputs = [ FundingInput.deserialize(fundingInput), FundingInput.deserialize(fundingInput), ]; expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if funding amount less than accept collateral satoshis', () => { instance.acceptCollateral = BigInt(3e8); expect(function () { instance.validate(); }).to.throw(Error); }); it('should allow single funded DLCs with zero acceptCollateral', () => { // Set up single funded DLC with zero collateral instance.acceptCollateral = BigInt(0); instance.fundingInputs = []; instance.markAsSingleFunded(); expect(function () { instance.validate(); }).to.not.throw(Error); }); it('should throw if single funded DLC funding amount is insufficient', () => { // Set up single funded DLC with insufficient funding instance.acceptCollateral = BigInt(300000000); instance.fundingInputs = []; instance.markAsSingleFunded(); expect(function () { instance.validate(); }).to.throw( 'For single funded DLCs, fundingAmount must be at least acceptCollateral', ); }); }); describe('Single Funded DLC Methods', () => { it('should correctly identify single funded DLCs', () => { // Initially not single funded expect(instance.isSingleFunded()).to.be.false; // Mark as single funded instance.markAsSingleFunded(); expect(instance.isSingleFunded()).to.be.true; }); it('should not identify regular DLCs as single funded', () => { // Default test setup has non-zero acceptCollateral expect(instance.isSingleFunded()).to.be.false; }); it('should mark DLC as single funded', () => { expect(function () { instance.markAsSingleFunded(); }).to.not.throw(Error); expect(instance.singleFunded).to.be.true; }); it('should auto-detect single funded DLCs during deserialization', () => { // Set up single funded DLC with zero collateral instance.acceptCollateral = BigInt(0); // Serialize and deserialize const serialized = instance.serialize(); const deserialized = DlcAccept.deserialize(serialized); // Should auto-detect as single funded expect(deserialized.singleFunded).to.be.true; expect(deserialized.isSingleFunded()).to.be.true; }); it('should not auto-detect regular DLCs as single funded', () => { // Default test setup has non-zero acceptCollateral const serialized = instance.serialize(); const deserialized = DlcAccept.deserialize(serialized); // Should not be detected as single funded expect(deserialized.singleFunded).to.be.false; expect(deserialized.isSingleFunded()).to.be.false; }); }); }); describe('DlcAcceptContainer', () => { it('should serialize and deserialize', () => { // Create two distinct accepts const dlcAccept = instance; const dlcAccept2 = new DlcAccept(); Object.assign(dlcAccept2, dlcAccept); dlcAccept2.payoutSpk = changeSpk; // Use different SPK dlcAccept2.changeSpk = payoutSpk; const container = new DlcAcceptContainer(); container.addAccept(dlcAccept); container.addAccept(dlcAccept2); const deserialized = DlcAcceptContainer.deserialize( container.serialize(), ); expect(container.serialize()).to.deep.equal(deserialized.serialize()); }); }); });