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

Example how to interact with smart contract once token is locked #440

Open
AdamMachera opened this issue May 24, 2022 · 1 comment
Open

Comments

@AdamMachera
Copy link

Hi guys,

I'm trying to migrate my marketplace from version 9.1.4 to version 10.1.0.

I was able to lock token in the smartcontract

export const offer = async (api: CardanoApi, policyId: string, assetName: string, askingPrice: string): Promise<string> => {
    const cardano = cardanoApiAdapter(api)
    const protocolParameters = await getProtocolProtocolParams()
    setupCoinSelector(protocolParameters)

    const txBuilder = await createTransactionBuilder(protocolParameters)
    const selfAddress = await cardano.getWalletAddress()
    const baseAddress = BaseAddress.from_address(selfAddress)!
    const pkh = toHex(baseAddress.payment_cred().to_keyhash()?.to_bytes() as Uint8Array);

    const transactionWitnessSet = TransactionWitnessSet.new();

    const offerDatum = createSalesOfferDatum(pkh, askingPrice, policyId, assetName);
    const offerDatumHash = hash_plutus_data(toPlutusData(offerDatum));
    //console.log(`offerDatumHash ${offerDatumHash} pkh: ${pkh} askingPrice: ${askingPrice} policyId: ${policyId} assetName: ${assetName}`);
    const contractOutput = TransactionOutput.new(
        getContractAddress(),
        getContractOutput(nftMoveFixedPrice, policyId, assetName)
    );
    contractOutput.set_data_hash(offerDatumHash);

    const utxos  = TransactionUnspentOutputs.new();
    const walletOutputs  = await cardano.getUtxos();
    walletOutputs.forEach(utxo => utxos.add(utxo))

    const aux_data: AuxiliaryData = await addOfferMetadata(txBuilder, selfAddress, askingPrice, assetName, policyId, "offer")

    txBuilder.add_output(contractOutput);
    txBuilder.add_inputs_from(utxos, 3)
    txBuilder.add_change_if_needed(selfAddress);
    const txBody = txBuilder.build();

    const transaction = Transaction.new(
        txBody,
        transactionWitnessSet,
        aux_data
    );

    logTxDetails(transaction)

    let signedtxVkeyWitnesses: TransactionWitnessSet
    try {
        signedtxVkeyWitnesses = await cardano.signTx(transaction, true);
    }
    catch (err) {
        throw handleSignError(err)
    }

    transactionWitnessSet.set_vkeys(signedtxVkeyWitnesses.vkeys()!);

    const signedTx = Transaction.new(
        txBody,
        transactionWitnessSet,
        transaction.auxiliary_data()
    );

    try {
        const txHash = await cardano.submitTx(signedTx);
        console.log(`txHash for sales offer: ${txHash}`);
        return txHash
    } catch (err) {
        appInsights.trackException({ exception: err as Error }, {
            sellerAddress: selfAddress.to_bech32(),
            sellerPkh: pkh,
            policyId: policyId,
            assetName: assetName,
            price: askingPrice,
            method: "offer"
        });
        throw err;
    }
}

However I'm struggling to figure out what I'm doing wrong when creating e.g. cancelation transaction (commented out code is some leftovers from the version 9.1.4):


export const cancel = async (api: CardanoApi, policyId: string, assetName: string): Promise<string> => {
    const cardano = cardanoApiAdapter(api)

    const protocolParameters = await getProtocolProtocolParams()
    setupCoinSelector(protocolParameters)

    console.log('cancel start1')
    const txBuilder = await createTransactionBuilder(protocolParameters)
    const unspentOutput = await getUnspentTransactionUtxoForNft(getContractAddress(), policyId, assetName);
    const transactionWitnessSet = TransactionWitnessSet.new();
    const selfAddress = Address.from_bech32(unspentOutput.metadata?.addr.join("") as string)
    const baseAddress = BaseAddress.from_address(selfAddress)!
    const pkh = toHex(baseAddress.payment_cred().to_keyhash()?.to_bytes() as Uint8Array);

    var scriptLockedValue = await getContractOutput(nftMoveFixedPrice, policyId, assetName)
    const outputs: TransactionOutput[] = [
        TransactionOutput.new(
            selfAddress,
            scriptLockedValue
        )
    ];

    const aux_data: AuxiliaryData = await addOfferMetadata(txBuilder, selfAddress, unspentOutput.metadata?.price as string, assetName, policyId, "cancel")
    const scriptInputIndex = unspentOutput.scriptUtxo.input().index();
    const utxos  = TransactionUnspentOutputs.new();
    const walletOutputs  = await cardano.getUtxos();
    walletOutputs.forEach(utxo => utxos.add(utxo))
    utxos.add(unspentOutput.scriptUtxo)
    // txBuilder.add_input(getContractAddress(), unspentOutput.scriptUtxo.input(), scriptLockedValue)
    txBuilder.add_output(outputs[0]);
    txBuilder.add_inputs_from(utxos, 3)
    txBuilder.add_change_if_needed(selfAddress);
    txBuilder.set_auxiliary_data(aux_data)

    const requiredSigners = Ed25519KeyHashes.new();
    requiredSigners.add(baseAddress.payment_cred().to_keyhash() as Ed25519KeyHash);
    // txBuilder.set_required_signers(requiredSigners);

    const salesOfferDatum = createSalesOfferDatum(pkh, unspentOutput.metadata?.price as string, policyId, assetName);
    const datum = toPlutusData(salesOfferDatum);
    const datumList = PlutusList.new();
    datumList.add(datum);

    const redeemers = Redeemers.new();
    redeemers.add(createRedeemer(scriptInputIndex, RedeemerType.Close));
    // txBuilder.set_plutus_scripts(getContractScript());
    // txBuilder.set_plutus_data(datumList);
    // txBuilder.set_redeemers(redeemers);

    transactionWitnessSet.set_plutus_scripts(getContractScript());
    transactionWitnessSet.set_plutus_data(datumList);
    transactionWitnessSet.set_redeemers(redeemers);
    
    const plutusWitness: PlutusWitness = PlutusWitness.new(getContractScriptV2(), datum, createRedeemer(scriptInputIndex, RedeemerType.Close))
    const witnesses = PlutusWitnesses.new()
    witnesses.add(plutusWitness)
    txBuilder.add_required_plutus_input_scripts(witnesses)

    console.log('cancel start4')
    const collateralUnspentTransactions = await getCollateralUnspentTransactionOutput(api);
    const collateralInputs = TransactionInputs.new();
    collateralUnspentTransactions.forEach(c => collateralInputs.add(c.input()));
    // txBuilder.set_collateral(collateralInputs);
    // txBuilder.add_change_if_needed(selfAddress);
    // txBuilder.set_fee(BigNum.from_str("1200000"))

    console.log('cancel start5')
    const transaction = txBuilder.build_tx();
    transaction.body().set_required_signers(requiredSigners)
    transaction.body().set_collateral(collateralInputs)
    // txBody.set_required_signers(requiredSigners);
    // txBody.set_collateral(collateralInputs);
    // const transaction = Transaction.new(
    //     txBody,
    //     transactionWitnessSet,
    //     aux_data
    // );

    let signedtxVkeyWitnesses: TransactionWitnessSet
    try {
        signedtxVkeyWitnesses = await cardano.signTx(transaction, true);
    }
    catch (err) {
        console.log(err)
        throw handleSignError(err)
    }

    transactionWitnessSet.set_vkeys(signedtxVkeyWitnesses.vkeys()!);
    const signedTx = Transaction.new(
        transaction.body(),
        transactionWitnessSet,
        transaction.auxiliary_data()
    );

    logTxDetails(signedTx)

    try
    {
        let txHash = await cardano.submitTx(signedTx);
        console.log(`cancel txhash: ${txHash}`)
        return txHash
    } catch (err) {
        console.log(err)
        appInsights.trackException({ exception: err as Error }, {
            sellerAddress: selfAddress.to_bech32(),
            sellerPkh: pkh,
            policyId: policyId,
            assetName: assetName,
            price: unspentOutput.metadata?.price as string,
            method: "cancel"
        });
        throw err;
    }
}

It would be nice if you can provide example of e.g. locking some funds with datum in SC and how later spent from SC using datum and redeemer.

Currently I'm getting
"Not enought ADA leftover to include non-ADA assets in a change address"
so probably I'm passing some wrong inputs but I'm passing utxos from wallet + adding input and its hash from SC on which NFT is laying.

@jinglescode
Copy link

@AdamMachera, a guide on how to lock and unlock token from smart contract, datum and redeemer.

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