Page MenuHomePhabricator

[Cashtab] Minimize fees for NFT listing txs
ClosedPublic

Authored by bytesofman on Oct 7 2024, 23:56.

Details

Reviewers
emack
Group Reviewers
Restricted Project
Commits
rABCc19651314fac: [Cashtab] Minimize fees for NFT listing txs
Summary

Cashtab currently requires a user balance of 3000 satoshis to list an NFT. This is bc the way Cashtab build's NFT listing txs -- which require a special "ad prep" tx -- was not fully developed.

Minimize the size of the double tx by ensuring the 2nd tx always has one input. Calculate the required fee of the 2nd tx (the offer tx) so that the 1st tx (the "ad prep" tx) can create an output that is exactly big enough to cover the offer tx with no change.

Test Plan

npm test

Diff Detail

Repository
rABC Bitcoin ABC
Branch
cheaper-nft-listings
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 30515
Build 60547: Build Diffecash-lib-tests · cashtab-tests
Build 60546: arc lint + arc unit

Event Timeline

Failed tests logs:

====== CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for minimum eCash fee ======
TypeError: Cannot read properties of undefined (reading 'copy')
    at copy (/work/modules/ecash-lib/src/tx.ts:178:31)
    at TxBuilder.prepareOutputs (/work/modules/ecash-lib/src/txBuilder.ts:113:44)
    at TxBuilder.prepareOutputs [as sign] (/work/modules/ecash-lib/src/txBuilder.ts:121:63)
    at sign (/work/cashtab/src/slpv1/index.js:665:36)
    at Object.<anonymous> (/work/cashtab/src/slpv1/__tests__/index.test.js:427:35)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for a different fee level ======
TypeError: Cannot read properties of undefined (reading 'copy')
    at copy (/work/modules/ecash-lib/src/tx.ts:178:31)
    at TxBuilder.prepareOutputs (/work/modules/ecash-lib/src/txBuilder.ts:113:44)
    at TxBuilder.prepareOutputs [as sign] (/work/modules/ecash-lib/src/txBuilder.ts:121:63)
    at sign (/work/cashtab/src/slpv1/index.js:665:36)
    at Object.<anonymous> (/work/cashtab/src/slpv1/__tests__/index.test.js:437:35)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for minimum eCash fee
CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for a different fee level

Failed tests logs:

====== CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for minimum eCash fee ======
TypeError: Cannot read properties of undefined (reading 'copy')
    at copy (/work/modules/ecash-lib/src/tx.ts:178:31)
    at TxBuilder.prepareOutputs (/work/modules/ecash-lib/src/txBuilder.ts:113:44)
    at TxBuilder.prepareOutputs [as sign] (/work/modules/ecash-lib/src/txBuilder.ts:121:63)
    at sign (/work/cashtab/src/slpv1/index.js:665:36)
    at Object.<anonymous> (/work/cashtab/src/slpv1/__tests__/index.test.js:427:35)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for a different fee level ======
TypeError: Cannot read properties of undefined (reading 'copy')
    at copy (/work/modules/ecash-lib/src/tx.ts:178:31)
    at TxBuilder.prepareOutputs (/work/modules/ecash-lib/src/txBuilder.ts:113:44)
    at TxBuilder.prepareOutputs [as sign] (/work/modules/ecash-lib/src/txBuilder.ts:121:63)
    at sign (/work/cashtab/src/slpv1/index.js:665:36)
    at Object.<anonymous> (/work/cashtab/src/slpv1/__tests__/index.test.js:437:35)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for minimum eCash fee
CashTab Unit Tests: slpv1 methods getAgoraAdFuelSats correctly determines one-input fee for an agora offer tx getAgoraAdFuelSats for a different fee level

remove debug log, patch tests

bytesofman published this revision for review.Oct 8 2024, 00:32
bytesofman added inline comments.
cashtab/src/components/Etokens/__tests__/TokenActions.test.js
663

can see that the output is 30 XEC in the old one

image.png (703×793 px, 75 KB)

663

vs 11.78 XEC now

image.png (703×793 px, 79 KB)

674

I still run into issues decoding these with electrum (5.2.13)

but can run with through bitcoin-cli decoderawtransaction

you can see that, before this diff, there is a change tx -- we didn't need all of that 30 XEC after all.

{
  "txid": "d732c995d4071786a689dff175c60982c57a14a3e2f6362ee0418fba6a5eca7f",
  "hash": "d732c995d4071786a689dff175c60982c57a14a3e2f6362ee0418fba6a5eca7f",
  "version": 2,
  "size": 348,
  "locktime": 0,
  "vin": [
    {
      "txid": "6543a807c83363e5d43587dcd15239b9c82a485e2b1ebbd730e82a0f0db4385f",
      "vout": 1,
      "scriptSig": {
        "asm": "810698561 4f4e4553484f54 6c8c3c5fb1d038dcce630a1504a04c2333c50fddfbb35b37c01ad4e89f0e2aae103703f2a2cf94cef51cbeff6c442feb961f4ec2fc948d59dc61b6ee83b3f262[ALL|FORKID] 222b50fe00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac7521031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dad074f4e4553484f5488044147523087",
        "hex": "0441475230074f4e4553484f54416c8c3c5fb1d038dcce630a1504a04c2333c50fddfbb35b37c01ad4e89f0e2aae103703f2a2cf94cef51cbeff6c442feb961f4ec2fc948d59dc61b6ee83b3f262414c56222b50fe00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac7521031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dad074f4e4553484f5488044147523087"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_RETURN 5262419 65 1145980243 5d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a2228326 0000000000000001",
        "hex": "6a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a2228326080000000000000001",
        "type": "nulldata"
      }
    },
    {
      "value": 5.46,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_HASH160 729833ae294590bbcf28bfbb9ad54c01b6cdb628 OP_EQUAL",
        "hex": "a914729833ae294590bbcf28bfbb9ad54c01b6cdb62887",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "ecash:ppefsvaw99zepw709zlmhxk4fsqmdndk9q4t9gc3jm"
        ]
      }
    },
    {
      "value": 17.54,
      "n": 2,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 00549451e5c22b18686cacdf34dce649e5ec3be2 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a91400549451e5c22b18686cacdf34dce649e5ec3be288ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "ecash:qqq9f9z3uhpzkxrgdjkd7dxuuey7tmpmugpmnw0kue"
        ]
      }
    }
  ]
}
674

no change here bc we pre-calculated the fee

{
  "txid": "97cf0fed5062419ad456f22457cfeb3b15909f1de2350be48c53b24944e0de89",
  "hash": "97cf0fed5062419ad456f22457cfeb3b15909f1de2350be48c53b24944e0de89",
  "version": 2,
  "size": 314,
  "locktime": 0,
  "vin": [
    {
      "txid": "7b4f2b1cf9716ead03f91910bd0c08956c381987e1cb3cd9f9b4d555a7b9ba25",
      "vout": 1,
      "scriptSig": {
        "asm": "810698561 4f4e4553484f54 06bd7c3cc4f6aca45a7f97644b8cb5e745dee224246f38605171e8f9e0d6e036af3ea4853b08e1baa92e091bd0ceabf83d4a246e07e6b0b008a3e091b111f22a[ALL|FORKID] 222b50fe00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac7521031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dad074f4e4553484f5488044147523087",
        "hex": "0441475230074f4e4553484f544106bd7c3cc4f6aca45a7f97644b8cb5e745dee224246f38605171e8f9e0d6e036af3ea4853b08e1baa92e091bd0ceabf83d4a246e07e6b0b008a3e091b111f22a414c56222b50fe00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac7521031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dad074f4e4553484f5488044147523087"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_RETURN 5262419 65 1145980243 5d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a2228326 0000000000000001",
        "hex": "6a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a2228326080000000000000001",
        "type": "nulldata"
      }
    },
    {
      "value": 5.46,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_HASH160 729833ae294590bbcf28bfbb9ad54c01b6cdb628 OP_EQUAL",
        "hex": "a914729833ae294590bbcf28bfbb9ad54c01b6cdb62887",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "ecash:ppefsvaw99zepw709zlmhxk4fsqmdndk9q4t9gc3jm"
        ]
      }
    }
  ]
}
This revision is now accepted and ready to land.Oct 8 2024, 11:01