Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maker ignores premium set in SwapInAgreement message #151

Open
remyers opened this issue Nov 7, 2022 · 4 comments
Open

Maker ignores premium set in SwapInAgreement message #151

remyers opened this issue Nov 7, 2022 · 4 comments

Comments

@remyers
Copy link

remyers commented Nov 7, 2022

I'm doing integration testing between PeerSwap CLN commit d1d88e4 and Eclair Swap Plugin SNAPSHOT 49823db. This testing was done with regtest.

Setup: Alice = Eclair node, Carol = CLN node

Repo:

  • Carol requests swap with Alice:
% carol-clightning-cli peerswap-swap-in 100001 $SCID_AC btc true
{
  "id": "a4cdf6c2d771c3a0dbfcda0ed96b54cf3c6fa5f2c419772af8e80a62ed359354",
  "created_at": 1667829916,
  "asset": "btc",
  "type": "swap-in",
  "role": "sender",
  "state": "State_SwapInSender_SendTxBroadcastedMessage",
  "initiator_node_id": "02dc9302720a5a6f3269bf2c71443a03e42d860294bf8d3200824b6cc649db5cff",
  "peer_node_id": "0378c9bb94dd3fd44902fdafbd4dc3fd7d97162b09a9fe424e066b462838555cbf",
  "amount": 100001,
  "channel_id": "9471x1x0",
  "opening_tx_id": "7666c19197ebd0ed089a4803edf8018f4314fe2789a940251a2393a08b125be2",
  "lnd_chan_id": 10413474626732032
}
  • Negotiation proceeds to point where Alice validates the OpeningTx and fails because the output amount is 100001, even though Alice requested a premium of 22237 sats, which is computed by Alice as feeRatePerKw * claimByInvoiceTxWeight / 1000 .

  • The opening tx sent by CLN was:

{
  "txid": "7666c19197ebd0ed089a4803edf8018f4314fe2789a940251a2393a08b125be2",
  "hash": "ecc13ce77fc520ca3b376c465f744167a7b4920896b99b2bd0afa6c016c2dcb5",
  "version": 2,
  "size": 382,
  "vsize": 220,
  "weight": 880,
  "locktime": 9941,
  "vin": [
    {
      "txid": "6c867042fee3db88671fa47ee00368f0f67053dfe370b2d1ba533dba3ea4fb5f",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "304402201ea1b1f96aa020f1e0edfec76b649837dc03d47783e2b0689b8fd248032b7295022034fe920ae639505e3cb075aa35b3911bfcf71db3befc2eaced0b3ffbcde30cb401",
        "026bda48ab1f68d596989232286401b5510e1a42917b1af55b0a25fed9aae618c9"
      ],
      "sequence": 4294967293
    },
    {
      "txid": "c0512e235c6460a7a23478aa0bc35457f7e407d731594920fee62dd71d3dbfef",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "3044022028f3bf7117103412f6e67627668dee4e28521e75709c466a563765100d382ba502204d7714226c01e9477ab3afc5fd67cb0365f5eec7896b671c692406127088a4ac01",
        "036788e045fbb5fad1b413ecf1dc92ddc9046184a63f6ed723278bfd664ae99fd6"
      ],
      "sequence": 4294967293
    }
  ],
  "vout": [
    {
      "value": 0.00061457,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 cb3de0e289cf99e9697067e3c59539e369d86cc4",
        "desc": "addr(bcrt1qev77pc5fe7v7j6tsvl3ut9feud5asmxyjlnaj5)#fhsgywq8",
        "hex": "0014cb3de0e289cf99e9697067e3c59539e369d86cc4",
        "address": "bcrt1qev77pc5fe7v7j6tsvl3ut9feud5asmxyjlnaj5",
        "type": "witness_v0_keyhash"
      }
    },
    {
      "value": 0.00100001,
      "n": 1,
      "scriptPubKey": {
        "asm": "0 52d317fc35907954aae8c225a2f9ec6957a2da61cb1d584eac8ecf03592d807c",
        "desc": "addr(bcrt1q2tf30lp4jpu4f2hgcgj6970vd9t69knpevw4sn4v3m8sxkfdsp7qgkq236)#ddqx30u0",
        "hex": "002052d317fc35907954aae8c225a2f9ec6957a2da61cb1d584eac8ecf03592d807c",
        "address": "bcrt1q2tf30lp4jpu4f2hgcgj6970vd9t69knpevw4sn4v3m8sxkfdsp7qgkq236",
        "type": "witness_v0_scripthash"
      }
    }
  ]
}
@remyers
Copy link
Author

remyers commented Nov 7, 2022

One other question; why is "locktime" set in OpeningTx ?

@nepet
Copy link
Contributor

nepet commented Nov 7, 2022

Good catch!

I guess you found something that we put in the spec a long time ago which we haven't thought through nor implemented by now. This was some kind of placeholder for us to not forget to talk about this eventually.

Do you think the way the premium is negotiated right now is the way to go or should we have a discussion about how to design the premium and the negotiation for it?

@remyers
Copy link
Author

remyers commented Nov 8, 2022

This probably deserves some discussion. A good default goal is that the swap proposer pays the on-chain fees for the swap receiver. It gets tricky if the sender and receiver disagree on how to compute those fees. We can look to how on-chain fees in Lightning work for how to approach this problem.

Calculating the weights of a nominal transaction should be easier for PeerSwap since there are no HTLCs or other variables to consider. The fee environment is also less likely to change within the period of time the swap is in progress.

For example, when a maker proposes a swap-in to a taker, they should add to the swap amount in the opening transaction output the premium requested by the taker in the swap-in-agreement message. This premium should equal the amount of on-chain fees the taker expects to spend for the claim-by-invoice tx. By accepting the swap, the taker should get the amount promised on-chain, after fees.

Likewise, if the taker proposes a swap-out to the maker, then the maker should include the on-chain fees for the opening tx and pay-by-csv tx in the off-chain premium they expect for their fee invoice. This prevents them from being out-of-pocket on fees even if the swap-out proposer does not conclude the swap.

I'm currently using the following values for nominal transaction sizes, but these should be verified:

  val claimByInvoiceTxWeight = 593 // TODO: add test to confirm this is the actual weight of the claimByInvoice tx in vBytes
  val openingTxWeight = 610 // TODO: compute and add test to confirm this is the actual weight of the opening tx in vBytes

I realize now that I am not including a payByCsvWeight to the openingTxWeight used for the fee invoice, but I think we should add it so that the swap-out receiver is made whole if the swap fails.

Each party should perform the same calculation as their counter party to verify that the requested fee/premium is not unreasonable. I think there should be a setting for the maximum percent the feeRatePerKw can exceed what is expected when calculating these values. If the counter party asks for a higher amount, the swap is canceled with a message to indicate the fee mismatch. To be extra adversarial, you just fail the swap without saying why - otherwise your counter party will always increase fees to just below your threshold.

Until we get something sorted out, I'll just set these fees to 0 so I can continue integration testing.

@remyers
Copy link
Author

remyers commented Nov 8, 2022

A more meta part of this discussion includes the question: "why would anyone propose a swap if they have to pay the on-chain fees?" . The answer should be that after the swap, they expect to earn in transaction fees more then they paid in swap premium. Or perhaps because this is the lowest cost way to buy inbound (or outbound) liquidity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants