Hello!
I was failed to calculate Ex units when try to unlock fund. It throws below error:
evalResults = Result{successful=false, response='{"ScriptFailures":{}}', code=500, value=[]}
First I create a smart contract and build it to plutus.json.
use aiken/hash.{Blake2b_224, Hash}
use aiken/list
use aiken/transaction.{
OutputReference, ScriptContext, Spend, Transaction, TransactionId,
}
use aiken/transaction/credential.{VerificationKey}
type Datum {
data: Hash<Blake2b_224, VerificationKey>,
}
type Redeemer {
message: ByteArray,
}
validator {
fn validateTransaction(
datum: Datum,
redeemer: Redeemer,
context: ScriptContext,
) {
let signed = list.has(context.transaction.extra_signatories, datum.data)
let validMessage = redeemer.message == "I am groot!"
signed && validMessage
}
}
Then, I lock some ADA with datum is payment credential hash.
private void lockAda(double ada) throws CborSerializationException, ApiException {
String compileCode = "58ef010000323232323232323222232325333008323232533300b002100114a066e3cdd7180118040032450b4920616d2067726f6f7421003322323300100100322533301000114a026464a66601e66e3c00801452889980200200098098011bae30110013758601a601c601c601c601c601c601c601c601c600e6002600e0086eb8c004c01c0188c034004526136563253330083370e900000089919299980698078010a4c2c6eb8c034004c01801058c01800cc94ccc01ccdc3a400000226464a666018601c0042930b1bae300c0013005004163005003230053754002460066ea80055cd2ab9d5573caae7d5d0aba21";
PlutusScript lockScript = getPlutusScriptFromCompiledCode(compileCode, PlutusVersion.v2);
String scriptAddress = AddressProvider.getEntAddress(lockScript, Networks.preprod()).toBech32();
Log.d("quan5.nguyen", "scriptAddress = " + scriptAddress);
mAccount.getEnterpriseAddress().getPaymentCredentialHash().ifPresent(keyHash -> {
mDatum = BytesPlutusData.of(keyHash);
PlutusData datum = new ConstrPlutusData(0, ListPlutusData.of(mDatum));
Output scriptReferenceOutput = Output.builder()
.address(scriptAddress)
.qty(ADAConversionUtil.adaToLovelace(ada))
.assetName(CardanoConstants.LOVELACE)
.scriptRef(lockScript)
.datum(datum)
.inlineDatum(true)
.build();
TxBuilder scriptRefTxBuilder = scriptReferenceOutput.outputBuilder()
.buildInputs(InputBuilders.createFromSender(mSenderAddress, mSenderAddress))
.andThen(BalanceTxBuilders.balanceTx(mSenderAddress, 1));
Transaction signedTx = TxBuilderContext.init(mUtxoSupplier, mProtocolParamsSupplier)
.buildAndSign(scriptRefTxBuilder, signerFrom(mAccount));
Result<String> result = null;
try {
result = mBackendService.getTransactionService().submitTransaction(signedTx.serialize());
} catch (ApiException | CborSerializationException e) {
throw new RuntimeException(e);
}
Log.d("quan5.nguyen", "lock result = " + result);
waitForTransactionHash(result);
});
}
After lock done, I continue to unlock ADA by tx hash but it fail when estimate Ex unit.
private void sendLockedAda() throws ApiException, CborSerializationException {
Log.d("quan5.nguyen", "sendLockedAda: ");
String compileCode = "58ef010000323232323232323222232325333008323232533300b002100114a066e3cdd7180118040032450b4920616d2067726f6f7421003322323300100100322533301000114a026464a66601e66e3c00801452889980200200098098011bae30110013758601a601c601c601c601c601c601c601c601c600e6002600e0086eb8c004c01c0188c034004526136563253330083370e900000089919299980698078010a4c2c6eb8c034004c01801058c01800cc94ccc01ccdc3a400000226464a666018601c0042930b1bae300c0013005004163005003230053754002460066ea80055cd2ab9d5573caae7d5d0aba21";
PlutusScript lockScript = getPlutusScriptFromCompiledCode(compileCode, PlutusVersion.v2);
mAccount.getEnterpriseAddress().getPaymentCredentialHash().ifPresent(keyHash -> {
mDatum = BytesPlutusData.of(keyHash);
});
PlutusData datumKeyHash = new ConstrPlutusData(0, ListPlutusData.of(mDatum));
String scriptAddress = AddressProvider.getEntAddress(lockScript, Networks.preprod()).toBech32();
Log.d("quan5.nguyen", "scriptAddress = " + scriptAddress);
PlutusData datum = BytesPlutusData.of("I'm groot!");
Utxo scriptUtxo = ScriptUtxoFinders.findFirstByDatumHashUsingDatum(mUtxoSupplier, scriptAddress, datumKeyHash).orElseThrow();
BigInteger claimAmount = scriptUtxo.getAmount().stream().filter(amount -> CardanoConstants.LOVELACE.equals(amount.getUnit()))
.findFirst()
.orElseThrow()
.getQuantity();
UtxoSelectionStrategy utxoSelectionStrategy = new DefaultUtxoSelectionStrategyImpl(mUtxoSupplier);
Set<Utxo> collateralUtxos = utxoSelectionStrategy
.select(mSenderAddress, new Amount(CardanoConstants.LOVELACE, ADAConversionUtil.adaToLovelace(5)), Collections.emptySet());
Output output = Output.builder()
.address(mSenderAddress)
.assetName(CardanoConstants.LOVELACE)
.qty(claimAmount)
.build();
ScriptCallContext scriptCallContext = ScriptCallContext.builder()
.script(lockScript)
.exUnits(ExUnits.builder()
.mem(BigInteger.valueOf(0))
.steps(BigInteger.valueOf(0))
.build()
)
.redeemer(datum)
.redeemerTag(RedeemerTag.Spend)
.build();
Utxo refScriptUtxo = Utxo.builder()
.txHash("7f8512e9aa6977f036cac1299bc637c731fb6758dd8f80aa1d71671cfc197681")
.outputIndex(0)
.build();
List<Utxo> utxoList = new ArrayList<>(collateralUtxos);
List<Utxo> scriptList = new ArrayList<>();
scriptList.add(refScriptUtxo);
List<Utxo> refScriptUtxoList = new ArrayList<>();
refScriptUtxoList.add(refScriptUtxo);
TxBuilder contractTxBuilder = output.outputBuilder()
.buildInputs(InputBuilders.createFromUtxos(scriptList))
.andThen(InputBuilders.referenceInputsFromUtxos(refScriptUtxoList))
.andThen(CollateralBuilders.collateralOutputs(mSenderAddress, utxoList))
.andThen(ScriptCallContextProviders.createFromScriptCallContext(scriptCallContext))
.andThen((context, txn) -> {
ExUnits estimatedExUnits;
try {
estimatedExUnits = evaluateExUnits(txn);
Log.d("quan5.nguyen", "estimatedExUnits = " + estimatedExUnits);
txn.getWitnessSet().getRedeemers().get(0).setExUnits(estimatedExUnits);
} catch (Exception e) {
throw new ApiRuntimeException("Script cost evaluation failed", e);
}
//Remove script from witnessset as we are using reference script input
txn.getWitnessSet().getPlutusV2Scripts().clear();
})
.andThen(BalanceTxBuilders.balanceTx(mSenderAddress, 2));
TxBuilderContext txBuilderContext = TxBuilderContext.init(mUtxoSupplier, mProtocolParamsSupplier);
TxSigner signer = signerFrom(mAccount);
Transaction signedTx = txBuilderContext.buildAndSign(contractTxBuilder, signer);
Result<String> result = mBackendService.getTransactionService().submitTransaction(signedTx.serialize());
Log.d("quan5.nguyen", "sendLockedAda: " + result);
}
I don’t know what wrong. Could you help me?
Thank you.