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

Helios API - Address::fromUplcData #72

Closed gavinharris-dev closed 1 year ago

gavinharris-dev commented 1 year ago

Unable to correctly convert an Address object back from Datum.

Test case on StackBlitz: https://stackblitz.com/edit/helios-address-issue?file=test/suite.test.ts

gavinharris-dev commented 1 year ago

Unsure of full ramifications, however the below seems to work:

I have tested for both Addresses with a Stake Key and addresses without; I've not tested all connotations of StakeKey (i.e., a Script Stake Address)

    /**
     * @param {UplcData} data 
     * @param {boolean} isTestnet
     * @returns {Address}
     */
    static fromUplcData(data, isTestnet = IS_TESTNET) {
        assert(data.index == 0);
        assert(data.fields.length == 2);

        const credData = data.fields[0];
        const stakData = data.fields[1];

        assert(credData.fields.length == 1);

        /**
         * @type {?(StakeKeyHash | StakingValidatorHash)}
         */
        let sh;

        if (stakData.fields.length == 0) {
            sh = null;
        } else {
            assert(stakData.fields.length == 1, "Stake Data not found");

            const inner = stakData.fields[0];
            assert(inner.fields.length == 1);

            if (inner.index == 0) {
                const innerInner = inner.fields[0];
                assert(innerInner.fields.length == 1);

                if (innerInner.index == 0) {
                    sh = new StakeKeyHash(innerInner.fields[0].bytes);
                } else if (innerInner.index == 1) {
                    sh = new StakingValidatorHash(innerInner.fields[0].bytes);
                } else {
                    throw new Error("unexpected");
                }
            } else if (inner.index == 1) {
                throw new Error("staking pointer not yet handled");
            } else {
                throw new Error("unexpected");
            }
        }

        if (credData.index == 0) {
            return Address.fromPubKeyHash(new PubKeyHash(credData.fields[0].bytes), sh, isTestnet);
        } else if (credData.index == 1) {
            return Address.fromValidatorHash(new ValidatorHash(credData.fields[0].bytes), sh, isTestnet);
        } else {
            throw new Error("unexpected");
        }
    }
christianschmitz commented 1 year ago

v0.13.5 fixes this. I hope I didn't keep you waiting too long

The issue was that I forgot that Option::None is encoded using index 1 instead of 0 in PlutusTx.

gavinharris-dev commented 1 year ago

This is great! I will throw away my patch that I was not 100% with!