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

Asset issuance not working as expected #108

Open
Distance71 opened this issue Sep 16, 2023 · 4 comments
Open

Asset issuance not working as expected #108

Distance71 opened this issue Sep 16, 2023 · 4 comments

Comments

@Distance71
Copy link

Distance71 commented Sep 16, 2023

Hello community,

I'm trying to create an asset with no success.

Everything looks well during the process of creation, but when I try to broadcast to the network I get this error:

sendrawtransaction RPC error: {"code":-26,"message":"mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)"}

To broadcast, I used https://blockstream.info/liquidtestnet/api/tx, passing the transactionHex in the body as 'text'

I've used the same methods as described in the examples provided

This's the full code needed to reproduce. Any help would be appreciated :)

const ecc = require('tiny-secp256k1');
  const secp256k1 = require('@vulpemventures/secp256k1-zkp');
  const liquid = require('liquidjs-lib');
  const { ECPairFactory } = require('ecpair');

  const ECPair = ECPairFactory(ecc);
  const TESTNET = liquid.networks.testnet;

  const makeAddressOne = () => {
  const keyPair = ECPair.fromPrivateKey(
    Buffer.from('acbc28e59c0122f97d479d1e22806534f5bc4ff0bf127505be7dd8a8e11dc726', 'hex'),
  );

  const { address } = liquid.payments.p2pkh({
    pubkey: keyPair.publicKey,
    network: TESTNET,
  });

  const blindkey = keyPair.publicKey;

  const { confidentialAddress } = liquid.payments.p2pkh({
    address,
    blindkey,
    network: TESTNET,
  });

  return {
    address,
    confidentialAddress,
    keys: keyPair,
  };
};

const convertAddressToScript = address => liquid.address.toOutputScript(address, TESTNET);


function signTransaction(pset, signers, sighashType, ecclib = ecc) {
  const signer = new liquid.Signer(pset);

  signers.forEach((keyPairs, i) => {
    const preimage = pset.getInputPreimage(i, sighashType);
    const partialSig = {
      partialSig: {
        pubkey: keyPairs.publicKey,
        signature: liquid.script.signature.encode(keyPairs.sign(preimage), sighashType),
      },
    };
    signer.addSignature(i, partialSig, liquid.Pset.ECDSASigValidator(ecclib));
  });

  if (!pset.validateAllSignatures(liquid.Pset.ECDSASigValidator(ecclib))) {
    throw new Error('Failed to sign pset');
  }

  const finalizer = new liquid.Finalizer(pset);
  finalizer.finalize();
  return liquid.Extractor.extract(pset);
}

  const addressAlice = makeAddressOne();
  const lbtc = liquid.networks.testnet.assetHash;

  const unspentConfidential = {
    txid: '337b9c5c8a4e83a56875d53b1ad9e7caa1c0862537bf040e4165b717560d9b38',
    vout: 1,
    txHex:
      '020000000101a16e6cfaecf3132c6b993862efd7ca882609850cf16332bc9ba48a729a2afed5010000006a473044022056a5198901f4b0d0e6d9cde19d0865ddd2028aece8b3b6740ba02e7d4aed85cc022050079be073d30b3e2cc5e2823e74e6ac139d48ea46c5601d433e8d69084ff2d701210382375b3986feb6f33d96f86c4bc5e09f53d7b3e4eb5b90eeca6d487b7eb40a65ffffffff0301499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000003e8001976a914539cc65863ecfbfce0dd163e9353cb29ea222c0a88ac0b6821f161c20add66bd7a4c3d4a85caf0dd69fcef2fc95a7a15485343e93e61ba093159ac773433fb919b9831f65dfddd250ce1e9afa9f00150a4fba2d79a868a4d033f3ba42f7268beebd479da75e97cd5bb6f791fec5dc545cd0db294110cbb38cc1976a9146db5192bb9ef2b8ba234d8e5b9399d4219419f9588ac01499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000003e800000000000000000000000043010001f59a88d5ac142a8dc48b088ad822e0e00305c1ded821d36e3dd2545e6c3dbdf9767d040e34a1d794e61ef558875435d3c953a1631fcc9c072b60eb64adf2691afd4e1060330000000000000001f5f06c009fc8e7035dc105984b6e61199fbac515d51ca3a0d8480675d927918f363b4b97cdd6ad2be78493dbdb268454c752df01c4cbba762ece262ba78e4a8bf014172304bc39b687269fa60354620178c11fd2f12261ab9e38d111d6d64214f7424b90ec96eef050d9fab83954d889d964d4607f8dab2939353d3f0d11ca3736e9ecf92cb94fe9b8ab3c56ddad2ec153ab226487d996f2debe0e247fa0448841a3ddaf09801ced01157d3876a82c6b6a9e3b610e529c33d5cbde73ff8a040a266c874182dc5f685e4bca2ba6b0b6cc03f328887c5457e65c600fd09027abb7c61231b71099fc5c8f386ad86313e3f096a89edfc18f52a151d8ec4627e418241dd040807c753d91e9c7feced79f80572e9cb01ad5dd4b63d1c0ba020d5371f15b0951d11873d277ba0959b88ffd50b7dc1abb1b7d046bfc754d629f477fc9bae94273763dd87a83dfd2dc599c99beef32163e900b0d678c589890d7b8d746e4dff39311919bc2add316acb35d2fcda02a8f428c50bead5d8784f323f490db4d5704b3d2a32edb0a46df72f69345aa3ff90c5e440df0f527ffdf3751763b9b00ee749d46d65672ffbcf880d274b08a74ea526c51db93bc45e22d4329ca7eef60084a26d1daf3a376721a2185d8c119518931d8d7e4fcf9799156e1e71c1bc65cfb6048062787655f67f8b3e51bfd2eb65612f0e86e547480b9890385e8101f0a8d566c71d5263da2257009f78a65aa51fa8dd8c5210f37f7ab7709e36e501937699a871f86ea08913cb14afbddc58bfd987b983bedab6aec29416b373fb84f6ec857f4959a215b403f0553966a4b9a90a99603c9d478fc18331d07cbcd4e59e911404152cc2526e25f7bc00d3e47f85c290047a4c88cd60190d2e432d34abeb6f6ac5852cb30ca12faf4d084ccf7f48e8a1144c640bcbcda5f4257e213e38cb17e174f6cbedc2f44c141bdafcfe4f3cdafcfa8abba1a25b168c405711a365a46145dafc65fdeff276138e822f4145bdf81f09eefb2cde5407a768dc2d460700327630e760625daf720e3f4ead348fea8651d20619ef05b45176ea4b97f45a946b742b7e52e3babc9d0a08cd6aeb7a06774302be3781d34e1d376d3a40315c02008a22da5037bd0adec9a9e0ec3f390c0325315b20aafa98736e184eb0ff3463660c8df6257ecfa4d27bb6c7019ca3649cf705401e02f5d9ef67b22abda8affc68becf290cb62da5fa4070a6c2aba2e76ac2d5c2347acec0458d6f53c446afe45867cdc81efb111c5da8b5b30ca2c0cb74b8c99a023737a9e6e4b0a1854056b69d662073764ef6dfd4f41f3bebda52e222528cd7758b09acf16bd253a1be01e55c4609b600ce148cd9daedd083d532ef200b4f5ebcffbd450e8f565ea5cba568670c7c80ab6104f4934c9d93d96ee5fe56bc2ec24f3915324e680cab7a1f46f79ddfdca13ca4d6fbb2fe2444261d2b6c4568b3cd0a555c29b97b483c645e7b40a478d4f8a1081cc34655860d05568a98dac98d00871bce511e1f062fa1f9d1a919327f6138f04307a618a8002c1dc42ff531ef985bc7a39e64d0a8da9a3aa23c639525d9ba05e3c0bfcc959413e0975ec6d67958016de07f9d5d782511546c3d8f22fbf21556e9b866181d101fe5367f4f5d0df3db30c289211f6adf88b0a186d08fad31b7672607117769045321d8b891e1c798fe1a14305f9fc47d820b2c36cddc106d1aa89ec21567f9f4cba037651276c820b3c410af61f52b5cb19499a1bc25b9e6edf3ba7dbaf8ecd302e40a20a6d411ceb717d25ce6e5f3a31c4afd0dd28b1317fc6edf7ddd28b5a6d44ec9ce47555120f3e76431f9133c477ad192c7df4d800f53ec7c9dc9b999c7d670f9d83c7849d33977f915296a0eefac14881e482a1b2c1d388769c0f5e47d77ffc765f4f74d152389246491e3a2545ece18f715b3afcf3dcd612f6902395ba69eeae2dd5540c74ff88516f19535579fb038f3e492286c10472a74f308a1d73e63aff33470a5c50401b3f671118c1146e0e671a737b12adb6d12a73d360bab1b4915a56265703c85921640502417498db9cd73f6a18c91b8d7c7412c359b1ab79f5e1a631ac7a1dc39567f03617b476b8f6fbb28eeb309c505eb01ed218ed687eedc41a55437763b71bb810ff2b2dd1332cd56346a99bf92e0cef1801afed09c5ee6a9112c40e29c854bfbeb0bd7988689a7f23c6363b4080d62934c8d6fa39485410e0dc54ddd78a231528cfdb2cf2465f9464a9b5f3a6ac5a821dfda6511a569fd488c434c3b5cc9cc88f25dcdea17fd0a7114793cc4b49800115059fdfb9b52781db0bb1e76e6260f927a1698154bebb701bb8f3e33c44f94cae3605e1627fafe392738e908a78da8115ca99382bda27fe6a184e5e865715de0092904cbde1f897ff63857e14e8390bcf965f7057ace53fb32388dd824ad622507c3e0f3df25e31f7ba0af33943d44630c6b15a0f78e1b54760905d23a481c3eedeeb3443009f76e5f9597f83c4ee3f4e376cf6a98bad707530038fe584eac28543dd3fcaccfefdd6b23a03a9a274d9f90fb8f06aae766a675e596cb279433477a9b41e60c9505d11e7335a4e116951cb2305b9cbf3a1ecc2521b66ed1cb111aaad5faaee99b6dbbaa2e12cb191658dae9abcab51ee273b384865b0fcc55c608ca6e4aa97eca8837cce737589a7370770681c9661159923bd12f36d73b0dbfb516628380357b8c50176d7cac52eb4118d2435e1f6386f796f7f152bba3c3b397ba32c2f0a2f7ab57e2df71301928e09971f1e9ce8859c00f46a98a02cf5633729d05838cb14aadab2dfe3a7510b1fce146d387f48f95b97e5177483a38902f98f771248e4b65ed23617db24c17ecd9733b675144cff0f8dd5a5a910355a94af5aa5bd8e718be1b22975853a4b4f9d8cbb69ae189fd4dda571b274484aed920a716295e1b637c5dd9c465fe89e5ccf8c6986e0a0defcf429145b86d40cefd03dc284c0dd8b8dfcc2e99ec7c0b7fd4b8fdf88b558ac0355cce913a254bdb427632ae032f91e3d82c1ee9bb7f08a3171d4fd01121f3b8e9c9941de5543de29309f6de0ef5113a88d66420b9d1926d1e42a2209f991aa5b58b2757f15fe3024bece53f490436ac91b0d6d9dcaa9c0116d5da4707f69d84c0b8bfeba931e8ba767d4f3b3f74854dbbe0799fb03671d4c1836677fa32df079a68e21e36e9dc877d06c1ce7e3da0f368094d32fc15f72e1d859acf37904d5cc86c16e829901893ca9e84c54764b883c885a4110083fce6db292af304f7e7f905cbdb12d519951758060b53c8c0f7e5bfba0664564e37cee01915d4f629ad1772537d5b1d33db5a09ed0ee0fd425502355f42c5d0906c2269405f6617e13552f619c03e3fd700ec61958fcd80cc209f15155c5bb16c4831a4759027a22e78389146818862209c503f6459df2d2db4228217b0e21f9f12b329e8d22841b044dbe2767bd407a2b033160680b928838097f89d63ed19f1091afe467f7589ae927373d56c82f9ea926ecc0238cb474676d22fe0aa3c1bd858570497fc467dd021c3764b27d84562f7420f320a8feea1d542e277280f5f65c637b8282c5bb8a1a1d566cc106ff26227f99fdb91df11bb7f98fc6313555ce21ea43c2492894329523473e58c74371cba40a0fec683cfb990c158f09eb2bf9166da0028b525f053c59ec00e4c5f79b014ce15a5accb1e0a02f60e6f416b53448f451cf44a7e892fdd4052abd92d30965f7716bb03b418e8b133f1a9116ba9fdd88621a1aa84932c67b5e0538f0980a6981bc946b4337c92fd91cd60ec4d2f116ad1ed7ea06cead4257255c9321c36fa6f53fc4d18df23f5f94c2662492982f93e1fa0277ac162fe145ebaf3c9c123e1c496bbaeca45b135b0c30f2b56d0a7692588bf8ec26406cf983e91f167f2a9bd8e8ffac9fcc704d8814352ec491e6cf00dbb388870dfcd8a126a50021dbb4b76da75d57277bf13d0b38c387bd4f84a333d0ad1e07420be83c6be593c23e34d3c7a626f90e11714cb98f4e4dc23daad01cd1a41580fba7c7f89dec325f240baaf9799d4ac99e983f9657219d011121e29b07e88dec8b1aea7b79466abd90518230dd4256fd8f3bf56ae1bf526daa41de9f3b4c82d5ff9efccc7a074c510d76748dd087431ebf9e96e7b626ef66a89a8c23383cd35f7b5d08e87fea79354431e30c30ce10ff9dc5acc6db3e084384343903aee579204182f061baa646f258ff3aa62d22172eb5ddabe45a17168db2fe5a051b6385967eab9cff2d4d065dcdc2142938e23caa54bf27b70f9a0710ae7499d817bd0937468e01130f874f93c988cb237b8c378bb0ec5d4a9b4466452e951a0a542cd736d28f9000368040ee7d53ac25651c1053508f145f92bef1a06c5301a702cc5aa0c1943089879878863f5413f18410942cb1517e1396d4dfa3f7b532566e3ac80612f422b2c9d5fed25381f786fa0ea79280921e532b997efcc1e5e13ffff5de30501eaea228c50004d90ad6f8e5604cf47e24d025558675ce07f007be3207ad9f7d4deeb89eb1f5267190baa3f7c663cb05d71c6a869976a259c2c2b70938dc922c87781bfebeb850d30b9a62a007ffca68b9bdc165565e3b2c14a9b36f09e46bc583ab14b5a8140cd1a6ec4d5c71115ceb3e37e82d803c3ad11bb134eb63899c33d6c98b0992ef6b7b9a552f3ddd812d467fdbf1f3af167c9c492d4360b425fc2ae2a8ab9997efb077174ac280770e72752bf16f7db0a2d6842387b392950185789f748130a9d67797fdc6d26cfac556ea08a3e14e084efe0a1df703eb8084994bf372939b8c9f80cc70b90f1627280653811e1253612b7bf0bed43dfd74636195f9a94066a17906b98fbb0979cd5d64d24a98618eab2254fb8eae726fb58a184ae6fdcd536709dd3338f3537e3ea1122c8b61518643c0f80c02fc15778efd297e36cf2a83fef59b2af9bea6d90a0057cc23773d28b2fd42a9122679aa858294f4739695be481b0ea5354b146119ad2a5b6ce3626c1447ee7768133afe7eb929a08613a1ca50614c247ce091d5f5b87a4702b8674e7ae850b6c26155d31c009c608dde266854a801bd4c73f68ee97d52c2475c4c5636e0e83863a2672e0a4f95d6875d0dcc10395d77dd11a6b448330ebd65dce4ec66cb430a55848bdc3c06738eb2c27aa24ef55722175a38ac2ef599ed346016a5db3c85a7c791607acc4e8bdca219032ed224648a3dddbab450deec0acb8ea7a2313afb5d40e386de05695cbd2a6e51e2fe4fb02ce8e4f41b5d2a4128cabd448c023e88a4fc1826cffd5d837c7236b6eb3b60353b1557e8ce7e7cdb5e7f8238a5db490ea5639e93a46778a6d64b4792ccad63f6b0aa3b05ff7e1347810a0ce553f58867b278bab4be3089be6fdae1eaf89e7d6e4b4141fcd33b87e0f3461aad9bb619791845c7bddcf9224b170ad3583b870b53634074e7f40524451925d21c39a35d7ba0c6a4c3c6d3f9fbcfbce04c3fd300cf91b63d981b6eceed8dfe26503395e075a9bfaf18b4e5e6725c187e86a338d9f149ed6b80d7d7b81b4f9ed108fa4843de62b685ea6162e8dd45b64c48d5ab6a9ae5c37142a077f1102e45d1941e4f506f0da83460d91dc3e12deef9bcb4945247cca64bd79780449475012b3084e6a6d442667df14199a2cc6eee54e6f39766087244c0d829aa2b1e83ac98f347910c5b106fea8fd9b4de3ea7954e5fafde3362414deaa1f864d24403c92be0d0db3504dd749445a9e5c345be9274a2cbc8a32a7c0839c6c1d5f30e0770cf048fd915d6dfa4212e2bbc1a56d93810a371b491fec13d46c13013dea5dcb3aca37cd193d79d8055613ddf3cca72f041799c282c584b0206fded0000',
    amount: 100000,
    asset: '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49',
  };

  const alice = {
    payment: {
      output: Buffer.from(convertAddressToScript(addressAlice.address), 'hex'),
      blindkey: addressAlice.keys.publicKey,
    },
    keys: addressAlice.keys,
    blindingKeys: [addressAlice.keys.privateKey],
  };

  const aliceInputData = {
    hash: Buffer.from(unspentConfidential.txid, 'hex').reverse(),
    index: unspentConfidential.vout, // index of utxo
    nonWitnessUtxo: unspentConfidential.txHex,
  };

  const inputs = [aliceInputData].map(({ hash, index }) => {
    const txid = hash
      .slice()
      .reverse()
      .toString('hex');
    return new liquid.CreatorInput(txid, index);
  });

  const outputs = [
    new liquid.CreatorOutput(
      unspentConfidential.asset,
      97000,
      alice.payment.output,
      alice.payment.blindkey,
      0,
    ),
    new liquid.CreatorOutput(lbtc, 1000),
  ];

  const zkpLib = await secp256k1();

  const pset = liquid.Creator.newPset({ inputs, outputs });
  const updater = new liquid.Updater(pset);

  updater.addInNonWitnessUtxo(0, liquid.Transaction.fromHex(aliceInputData.nonWitnessUtxo));
  updater.addInSighashType(0, liquid.Transaction.SIGHASH_ALL);

  const zkpValidator = new liquid.ZKPValidator(zkpLib);
  const zkpGenerator = new liquid.ZKPGenerator(
    zkpLib,
    liquid.ZKPGenerator.WithBlindingKeysOfInputs(alice.blindingKeys),
  );

  updater.addInIssuance(0, {
    assetAmount: 1000,
    assetAddress: addressAlice.confidentialAddress,
    blindedIssuance: true,
    contract: {
      entity: {
        domain: 'www.testbtset.com',
      },
      issuer_pubkey: addressAlice.confidentialAddress,
      name: 'TESTBTSET',
      precision: 0, // NFT
      ticker: 'TESTBTSET',
      version: 1.0,
      collection: 'test-btset-collection',
    },
  });

  const issuanceBlindingArgs = zkpGenerator.blindIssuances(pset, {
    0: alice.blindingKeys[0],
  });

  const ownedInputs = zkpGenerator.unblindInputs(pset);
  const outputBlindingArgs = zkpGenerator.blindOutputs(pset, liquid.Pset.ECCKeysGenerator(ecc));
  const blinder = new liquid.Blinder(pset, ownedInputs, zkpValidator, zkpGenerator);
  blinder.blindLast({ issuanceBlindingArgs, outputBlindingArgs });
  const rawTx = signTransaction(pset, [alice.keys], liquid.Transaction.SIGHASH_ALL);
@altafan
Copy link
Collaborator

altafan commented Sep 18, 2023

The error suggests that something's wrong with the input signature.

One thing I noticed is that you hardcoded the amount of the LBTC input to 100000, while the outputs add up to 98000. After unblinding the conf output, I made sure that the correct input amount is 98000 but, still, the same error persisted.

@Distance71
Copy link
Author

@altafan What may be wrong in the signature? I used the same method shown in the examples
@louisinger May you have some more background on this?

@altafan
Copy link
Collaborator

altafan commented Sep 19, 2023

@Distance71 we were able to reproduce your error, we're now debugging to understand where's the bug.

In the meantime, you could move all your funds to a p2wpkh address. We have working test cases that demonstrate how to make a successful issuance with this kind of addresses.

@Distance71
Copy link
Author

@altafan Any updates on this?

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