UNPKG

@node-dlc/messaging

Version:
548 lines (500 loc) 22 kB
import { expect } from 'chai'; import { LOCKTIME_THRESHOLD, MessageType, OrderOfferContainer, OrderPositionInfoV0, } from '../../lib'; import { ContractInfo } from '../../lib/messages/ContractInfo'; import { IOrderIrcInfoJSON, OrderIrcInfoV0, } from '../../lib/messages/OrderIrcInfo'; import { IOrderMetadataJSON, OrderMetadataV0, } from '../../lib/messages/OrderMetadata'; import { OrderOfferV0 } from '../../lib/messages/OrderOffer'; describe('OrderOffer', () => { const chainHash = Buffer.from( '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f', 'hex', ); const buf = Buffer.from( "f532" + // type "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + // chain_hash "fdd82e" + // type contract_info "fd0131" + // length "000000000bebc200" + // total_collateral "fda710" + // type contract_descriptor "79" + // length "03" + // num_outcomes "c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722" + // outcome_1 "0000000000000000" + // payout_1 "adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead" + // outcome_2 "00000000092363a3" + // payout_2 "6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288" + // outcome_3 "000000000bebc200" + // payout_3 "fda712" + // type oracle_info "a8" + // length "fdd824" + // type oracle_announcement "a4" + // length "fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9" + // announcement_signature_r "494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4" + // announcement_signature_s "da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b" + // oracle_public_key "fdd822" + // type oracle_event "40" + // length "0001" + // nb_nonces "3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b" + // oracle_nonces "00000000" + // event_maturity_epoch "fdd806" + // type enum_event_descriptor "10" + // length "0002" + // num_outcomes "06" + // outcome_1_len "64756d6d7931" + // outcome_1 "06" + // outcome_2_len "64756d6d7932" + // outcome_2 "05" + // event_id_length "64756d6d79" + // event_id "0000000005f5e100" + // total_collateral_satoshis "0000000000000001" + // fee_rate_per_vb "00000064" + // cet_locktime "000000c8" // refund_locktime , "hex" ); // prettier-ignore describe('serialize', () => { const instance = new OrderOfferV0(); instance.chainHash = chainHash; instance.contractInfo = ContractInfo.deserialize( Buffer.from( 'fdd82e' + // type contract_info 'fd0131' + // length '000000000bebc200' + // total_collateral 'fda710' + // type contract_descriptor '79' + // length '03' + // num_outcomes 'c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722' + // outcome_1 '0000000000000000' + // payout_1 'adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead' + // outcome_2 '00000000092363a3' + // payout_2 '6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288' + // outcome_3 '000000000bebc200' + // payout_3 'fda712' + // type oracle_info 'a8' + // length 'fdd824' + // type oracle_announcement 'a4' + // length 'fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9' + // announcement_signature_r '494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4' + // announcement_signature_s 'da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b' + // oracle_public_key 'fdd822' + // type oracle_event '40' + // length '0001' + // nb_nonces '3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b' + // oracle_nonces '00000000' + // event_maturity_epoch 'fdd806' + // type enum_event_descriptor '10' + // length '0002' + // num_outcomes '06' + // outcome_1_len '64756d6d7931' + // outcome_1 '06' + // outcome_2_len '64756d6d7932' + // outcome_2 '05' + // event_id_length '64756d6d79', // event_id 'hex', ), ); instance.offerCollateralSatoshis = BigInt(100000000); instance.feeRatePerVb = BigInt(1); instance.cetLocktime = 100; instance.refundLocktime = 200; it('serializes', () => { expect(instance.serialize().toString("hex")).to.equal( "f532" + // type "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + // chain_hash "fdd82e" + // type contract_info "fd0131" + // length "000000000bebc200" + // total_collateral "fda710" + // type contract_descriptor "79" + // length "03" + // num_outcomes "c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722" + // outcome_1 "0000000000000000" + // payout_1 "adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead" + // outcome_2 "00000000092363a3" + // payout_2 "6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288" + // outcome_3 "000000000bebc200" + // payout_3 "fda712" + // type oracle_info "a8" + // length "fdd824" + // type oracle_announcement "a4" + // length "fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9" + // announcement_signature_r "494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4" + // announcement_signature_s "da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b" + // oracle_public_key "fdd822" + // type oracle_event "40" + // length "0001" + // nb_nonces "3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b" + // oracle_nonces "00000000" + // event_maturity_epoch "fdd806" + // type enum_event_descriptor "10" + // length "0002" + // num_outcomes "06" + // outcome_1_len "64756d6d7931" + // outcome_1 "06" + // outcome_2_len "64756d6d7932" + // outcome_2 "05" + // event_id_length "64756d6d79" + // event_id "0000000005f5e100" + // total_collateral_satoshis "0000000000000001" + // fee_rate_per_vb "00000064" + // cet_locktime "000000c8" // refund_locktime ); // prettier-ignore }); it('serializes with metadata', () => { const metadata = new OrderMetadataV0(); metadata.offerId = 'strategy-88'; metadata.createdAt = 1635868041; metadata.goodTill = 1635868041; instance.metadata = metadata; expect(instance.serialize().toString('hex')).to.equal( "f532" + // type "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + // chain_hash "fdd82e" + // type contract_info "fd0131" + // length "000000000bebc200" + // total_collateral "fda710" + // type contract_descriptor "79" + // length "03" + // num_outcomes "c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722" + // outcome_1 "0000000000000000" + // payout_1 "adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead" + // outcome_2 "00000000092363a3" + // payout_2 "6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288" + // outcome_3 "000000000bebc200" + // payout_3 "fda712" + // type oracle_info "a8" + // length "fdd824" + // type oracle_announcement "a4" + // length "fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9" + // announcement_signature_r "494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4" + // announcement_signature_s "da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b" + // oracle_public_key "fdd822" + // type oracle_event "40" + // length "0001" + // nb_nonces "3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b" + // oracle_nonces "00000000" + // event_maturity_epoch "fdd806" + // type enum_event_descriptor "10" + // length "0002" + // num_outcomes "06" + // outcome_1_len "64756d6d7931" + // outcome_1 "06" + // outcome_2_len "64756d6d7932" + // outcome_2 "05" + // event_id_length "64756d6d79" + // event_id "0000000005f5e100" + // total_collateral_satoshis "0000000000000001" + // fee_rate_per_vb "00000064" + // cet_locktime "000000c8" + // refund_locktime "fdf536140b73747261746567792d383861815d8961815d89" // order_metadata_v0 tlv ); // prettier-ignore }); it('serializes with ircinfo', () => { const ircInfo = new OrderIrcInfoV0(); ircInfo.nick = 'A0F5k4H9C56xgbRF'; ircInfo.pubKey = Buffer.from( '022d40fdc0db01b85bb4de6fe181c093b69c3a4558b7fc98a22e289b9d8da1d6f3', 'hex', ); instance.ircInfo = ircInfo; expect(instance.serialize().toString('hex')).to.equal( "f532" + // type "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + // chain_hash "fdd82e" + // type contract_info "fd0131" + // length "000000000bebc200" + // total_collateral "fda710" + // type contract_descriptor "79" + // length "03" + // num_outcomes "c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722" + // outcome_1 "0000000000000000" + // payout_1 "adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead" + // outcome_2 "00000000092363a3" + // payout_2 "6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288" + // outcome_3 "000000000bebc200" + // payout_3 "fda712" + // type oracle_info "a8" + // length "fdd824" + // type oracle_announcement "a4" + // length "fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9" + // announcement_signature_r "494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4" + // announcement_signature_s "da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b" + // oracle_public_key "fdd822" + // type oracle_event "40" + // length "0001" + // nb_nonces "3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b" + // oracle_nonces "00000000" + // event_maturity_epoch "fdd806" + // type enum_event_descriptor "10" + // length "0002" + // num_outcomes "06" + // outcome_1_len "64756d6d7931" + // outcome_1 "06" + // outcome_2_len "64756d6d7932" + // outcome_2 "05" + // event_id_length "64756d6d79" + // event_id "0000000005f5e100" + // total_collateral_satoshis "0000000000000001" + // fee_rate_per_vb "00000064" + // cet_locktime "000000c8" + // refund_locktime "fdf536140b73747261746567792d383861815d8961815d89fdf5383210413046356b3448394335367867625246022d40fdc0db01b85bb4de6fe181c093b69c3a4558b7fc98a22e289b9d8da1d6f3" // order_irc_info_v0 tlv ); // prettier-ignore }); it('serializes with cso info', () => { const positionInfo = new OrderPositionInfoV0(); positionInfo.shiftForFees = 'offeror'; positionInfo.fees = BigInt(10000); instance.positionInfo = positionInfo; expect(instance.serialize().toString('hex')).to.equal( 'f532' + // type '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f' + // chain_hash 'fdd82e' + // type contract_info 'fd0131' + // length '000000000bebc200' + // total_collateral 'fda710' + // type contract_descriptor '79' + // length '03' + // num_outcomes 'c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722' + // outcome_1 '0000000000000000' + // payout_1 'adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead' + // outcome_2 '00000000092363a3' + // payout_2 '6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288' + // outcome_3 '000000000bebc200' + // payout_3 'fda712' + // type oracle_info 'a8' + // length 'fdd824' + // type oracle_announcement 'a4' + // length 'fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9' + // announcement_signature_r '494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4' + // announcement_signature_s 'da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b' + // oracle_public_key 'fdd822' + // type oracle_event '40' + // length '0001' + // nb_nonces '3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b' + // oracle_nonces '00000000' + // event_maturity_epoch 'fdd806' + // type enum_event_descriptor '10' + // length '0002' + // num_outcomes '06' + // outcome_1_len '64756d6d7931' + // outcome_1 '06' + // outcome_2_len '64756d6d7932' + // outcome_2 '05' + // event_id_length '64756d6d79' + // event_id '0000000005f5e100' + // total_collateral_satoshis '0000000000000001' + // fee_rate_per_vb '00000064' + // cet_locktime '000000c8' + // refund_locktime 'fdf536140b73747261746567792d383861815d8961815d89' + 'fdf5383210413046356b3448394335367867625246022d40fdc0db01b85bb4de6fe181c093b69c3a4558b7fc98a22e289b9d8da1d6f3' + 'fdf53a09010000000000002710', // order_irc_info_v0 tlv ); }); }); describe('deserialize', () => { it('deserializes', () => { const instance = OrderOfferV0.deserialize(buf); expect(instance.chainHash).to.deep.equal(chainHash); expect(instance.contractInfo.serialize().toString('hex')).to.equal( 'fdd82e' + // type contract_info 'fd0131' + // length '000000000bebc200' + // total_collateral 'fda710' + // type contract_descriptor '79' + // length '03' + // num_outcomes 'c5a7affd51901bc7a51829b320d588dc7af0ad1f3d56f20a1d3c60c9ba7c6722' + // outcome_1 '0000000000000000' + // payout_1 'adf1c23fbeed6611efa5caa0e9ed4c440c450a18bc010a6c867e05873ac08ead' + // outcome_2 '00000000092363a3' + // payout_2 '6922250552ad6bb10ab3ddd6981b530aa9a6fd05725bf85b59e3e51163905288' + // outcome_3 '000000000bebc200' + // payout_3 'fda712' + // type oracle_info 'a8' + // length 'fdd824' + // type oracle_announcement 'a4' + // length 'fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9' + // announcement_signature_r '494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4' + // announcement_signature_s 'da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0b' + // oracle_public_key 'fdd822' + // type oracle_event '40' + // length '0001' + // nb_nonces '3cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b' + // oracle_nonces '00000000' + // event_maturity_epoch 'fdd806' + // type enum_event_descriptor '10' + // length '0002' + // num_outcomes '06' + // outcome_1_len '64756d6d7931' + // outcome_1 '06' + // outcome_2_len '64756d6d7932' + // outcome_2 '05' + // event_id_length '64756d6d79', // event_id ); expect(Number(instance.offerCollateralSatoshis)).to.equal(100000000); expect(Number(instance.feeRatePerVb)).to.equal(1); expect(instance.cetLocktime).to.equal(100); expect(instance.refundLocktime).to.equal(200); }); it('deserializes with metadata', () => { const bufWithMetadata = Buffer.concat([ buf, Buffer.from('fdf5360c0b73747261746567792d3838', 'hex'), ]); const instance = OrderOfferV0.deserialize(bufWithMetadata); expect((instance.metadata as OrderMetadataV0).offerId).to.equal( 'strategy-88', ); }); it('deserializes with positioninfo', () => { const bufWithPositionInfo = Buffer.concat([ buf, Buffer.from('fdf53a09010000000000002710', 'hex'), ]); const instance = OrderOfferV0.deserialize(bufWithPositionInfo); expect( (instance.positionInfo as OrderPositionInfoV0).shiftForFees, ).to.equal('offeror'); expect((instance.positionInfo as OrderPositionInfoV0).fees).to.equal( BigInt(10000), ); }); }); describe('toJSON', () => { it('converts to JSON with metadata', async () => { const bufWithMetadata = Buffer.concat([ buf, Buffer.from('fdf5360c0b73747261746567792d3838', 'hex'), ]); const instance = OrderOfferV0.deserialize(bufWithMetadata); const json = instance.toJSON(); expect(json.type).to.equal(instance.type); expect(json.chainHash).to.equal(instance.chainHash.toString('hex')); expect(json.contractInfo.type).to.equal(instance.contractInfo.type); expect(json.contractInfo.totalCollateral).to.equal( Number(instance.contractInfo.totalCollateral), ); expect(json.feeRatePerVb).to.equal(Number(instance.feeRatePerVb)); expect(json.cetLocktime).to.equal(instance.cetLocktime); expect(json.refundLocktime).to.equal(instance.refundLocktime); expect(json.tlvs[0].type === MessageType.OrderMetadataV0).to.equal(true); expect((json.tlvs[0] as IOrderMetadataJSON).offerId).to.equal( (instance.metadata as OrderMetadataV0).offerId, ); }); it('converts to JSON with ircinfo', async () => { const bufWithIrcInfo = Buffer.concat([ buf, Buffer.from( 'fdf536140b73747261746567792d383861815d8961815d89fdf5383210413046356b3448394335367867625246022d40fdc0db01b85bb4de6fe181c093b69c3a4558b7fc98a22e289b9d8da1d6f3', 'hex', ), ]); const instance = OrderOfferV0.deserialize(bufWithIrcInfo); const json = instance.toJSON(); const i = json.tlvs.findIndex( (tlv) => tlv.type === MessageType.OrderIrcInfoV0, ); expect(json.tlvs[i].type === MessageType.OrderIrcInfoV0).to.equal(true); expect((json.tlvs[i] as IOrderIrcInfoJSON).nick).to.equal( (instance.ircInfo as OrderIrcInfoV0).nick, ); }); }); describe('validate', () => { let instance: OrderOfferV0; beforeEach(() => { instance = OrderOfferV0.deserialize(buf); }); it('should throw if offerCollateralSatoshis is less than 1000', () => { instance.offerCollateralSatoshis = BigInt(999); expect(function () { instance.validate(); }).to.throw( 'offer_collateral_satoshis must be greater than or equal to 1000', ); // boundary check instance.offerCollateralSatoshis = BigInt(1000); expect(function () { instance.validate(); }).to.not.throw(); }); it('should throw if cet_locktime is less than 0', () => { instance.cetLocktime = -1; expect(() => { instance.validate(); }).to.throw('cet_locktime must be greater than or equal to 0'); }); it('should throw if refund_locktime is less than 0', () => { instance.refundLocktime = -1; expect(() => { instance.validate(); }).to.throw('refund_locktime must be greater than or equal to 0'); }); it('should throw if cet_locktime and refund_locktime are not in same units', () => { instance.cetLocktime = 100; instance.refundLocktime = LOCKTIME_THRESHOLD + 200; expect(function () { instance.validate(); }).to.throw(Error); }); it('should not throw if cet_locktime and refund_locktime are in same units', () => { instance.cetLocktime = 100; instance.refundLocktime = 200; expect(function () { instance.validate(); }).to.not.throw(Error); instance.cetLocktime = LOCKTIME_THRESHOLD + 100; instance.refundLocktime = LOCKTIME_THRESHOLD + 200; expect(function () { instance.validate(); }).to.not.throw(Error); }); it('should throw if cet_locktime >= refund_locktime', () => { instance.cetLocktime = 200; instance.refundLocktime = 100; expect(function () { instance.validate(); }).to.throw(Error); instance.cetLocktime = 100; instance.refundLocktime = 100; expect(function () { instance.validate(); }).to.throw(Error); }); it('should throw if totalCollateral <= offerCollateral', () => { instance.contractInfo.totalCollateral = BigInt(200000000); instance.offerCollateralSatoshis = BigInt(200000000); expect(function () { instance.validate(); }).to.throw(Error); instance.contractInfo.totalCollateral = BigInt(200000000); instance.offerCollateralSatoshis = BigInt(200000001); expect(function () { instance.validate(); }).to.throw(Error); }); }); describe('OrderOfferContainer', () => { it('should serialize and deserialize', () => { const orderOffer = OrderOfferV0.deserialize(buf); // swap payout and change spk to differentiate between dlcoffers const orderOffer2 = OrderOfferV0.deserialize(buf); orderOffer2.refundLocktime = 300; const container = new OrderOfferContainer(); container.addOffer(orderOffer); container.addOffer(orderOffer2); const instance = OrderOfferContainer.deserialize(container.serialize()); expect(container.serialize()).to.deep.equal(instance.serialize()); }); }); });