HeliosLang / compiler

Helios is a DSL for writing Cardano smart contracts. This library lets you compile Helios scripts and build Cardano transactions.
https://www.hyperion-bt.org/helios-book
BSD 3-Clause "New" or "Revised" License
142 stars 31 forks source link

UTxO fromCbor fails when a refScript is present #112

Closed papag00se closed 11 months ago

papag00se commented 1 year ago

Cbor.decodeTuple takes a function as a 2nd param that gets called by Cbor.decodeList. Cbor.decodeList will always pass in 0 on the first iteration. When handling UTxO refScripts, the function that is passed in always throws an error for case 0. Therefore the other cases are never considered and the error native refScript unhandled is always thrown.

Discord conversation for context: https://discord.com/channels/997177025972424815/997177141177352229/1153483324434686013

There is another problem with wallet DApps that incorrectly change that tuple key from a 2 (PlutusV2) to a 1 when returning the UTxO via CIP-30. This compounds the problem with the above passed in function as case 1 also fails. We have a ticket open with Eternl to fix this (Lace also does this).

In order to get Helios to work with refScripts in a CIP-30 UTxO, we had to replace the following code:

Cbor.decodeTuple(tupleBytes, (tupleIdx, innerTupleBytes) => {
     assert(refScript === null);

     switch (tupleIdx) {
         case 0:
             throw new Error('native refScript unhandled');
         case 1:
             throw new Error('plutuScriptV1 as refScript unhandled');
         case 2:
             refScript = UplcProgram.fromCbor(innerTupleBytes);
         default:
             throw new Error('unhandled script type for refScript');
     }
});

with...

Cbor.decodeTuple(tupleBytes, (tupleIdx, innerTupleBytes) => {
    switch (tupleIdx) {
        case 0:
            console.warn('native refScript unhandled');
            break;
        case 1:
            // Needed temporarily to workaround Eternl/Lace bugs
            refScript = UplcProgram.fromCbor(innerTupleBytes.slice(1));
            break;
        case 2:
            refScript = UplcProgram.fromCbor(innerTupleBytes.slice(1));
            break;
        default:
            throw new Error('unhandled script type for refScript');
    }
});
papag00se commented 1 year ago

Ola from Eternl thinks their side of the bug is in CSL. That might explain why Lace does the same thing. He said they'll see what they can do to fix it on their side.

christianschmitz commented 1 year ago

The way I called decodeTuple was simply wrong, the tupleIdx isn't the refScriptType (rather: the refScriptType sits at tupleIdx ==0)

christianschmitz commented 12 months ago

v0.16.4 hopefully fixes this

papag00se commented 11 months ago

Fixed! Thank you