From fb9a86803a92b71fd125c0ed93c120bbbdc1cff5 Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Thu, 13 Nov 2025 23:24:07 +0100 Subject: [PATCH 1/2] Implement addition of certificates to transactions --- cardano-wasm/src-lib/Cardano/Wasm/Api/Tx.hs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cardano-wasm/src-lib/Cardano/Wasm/Api/Tx.hs b/cardano-wasm/src-lib/Cardano/Wasm/Api/Tx.hs index b85e024cde..eca2218e54 100644 --- a/cardano-wasm/src-lib/Cardano/Wasm/Api/Tx.hs +++ b/cardano-wasm/src-lib/Cardano/Wasm/Api/Tx.hs @@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} @@ -15,6 +16,7 @@ module Cardano.Wasm.Api.Tx , newConwayTxImpl , addTxInputImpl , addSimpleTxOutImpl + , appendCertificateToTxImpl , estimateMinFeeImpl , setFeeImpl , signWithPaymentKeyImpl @@ -125,6 +127,21 @@ addSimpleTxOutImpl (UnsignedTxObject era (Exp.UnsignedTx tx)) destAddr lovelaceA (Api.AsAddressInEra Api.asType) (Text.pack destAddrStr) +-- | Append a certificate (in CBOR hex string format) to an unsigned transaction object. +appendCertificateToTxImpl + :: (HasCallStack, MonadThrow m) => UnsignedTxObject -> String -> m UnsignedTxObject +appendCertificateToTxImpl (UnsignedTxObject era (Exp.UnsignedTx tx)) certCbor = do + Exp.Certificate cert <- deserialiseCertificate era certCbor + let tx' = tx & Ledger.bodyTxL . Ledger.certsTxBodyL %~ (<> StrictSeq.fromList [cert]) + return $ UnsignedTxObject era $ Exp.UnsignedTx tx' + where + deserialiseCertificate + :: (HasCallStack, MonadThrow m) => Exp.Era era -> String -> m (Exp.Certificate (Exp.LedgerEra era)) + deserialiseCertificate era' certCbor' = + obtainCommonConstraints era' $ + rightOrError $ + Api.deserialiseFromCBOR Exp.AsCertificate (Text.encodeUtf8 $ Text.pack certCbor') + -- | Set the fee for an unsigned transaction object. setFeeImpl :: UnsignedTxObject -> Ledger.Coin -> UnsignedTxObject setFeeImpl (UnsignedTxObject era (Exp.UnsignedTx tx)) fee = From 0dd7ea5cf15a22ef0fcba6db0d0e542732241f94 Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Thu, 13 Nov 2025 23:24:52 +0100 Subject: [PATCH 2/2] Expose `appendCertificateToTx` in the JS API --- cardano-wasm/js-test/basic-test.spec.ts | 2 +- cardano-wasm/lib-wrapper/unsigned-tx.d.ts | 7 +++++++ cardano-wasm/src-lib/Cardano/Wasm/Api/Info.hs | 10 ++++++++++ .../Cardano/Wasm/Internal/JavaScript/Bridge.hs | 13 +++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cardano-wasm/js-test/basic-test.spec.ts b/cardano-wasm/js-test/basic-test.spec.ts index ee6339ff6d..13a5cde6f3 100644 --- a/cardano-wasm/js-test/basic-test.spec.ts +++ b/cardano-wasm/js-test/basic-test.spec.ts @@ -8,5 +8,5 @@ test('test output matches', async ({ page }) => { // Wait for the test to finish running (we signal this by creating a tag with id "finish-tag" and text "Finished test!") await expect(page.locator('#finish-tag')).toHaveText("Finished test!"); // Check the output of the test (from the example folder), which is displayed in the code element with id "test-output". The output contains information about the various objects and results of trying some of the functions. - await expect(page.locator('#test-output')).toHaveText("> \"Api object:\"> [object] { objectType: cardano-api tx: [object Object] newGrpcConnection: async function (...args) wallet: [object Object] }> \"Bech32 of address:\"> \"addr_test1vp93p9em3regvgylxuvet6fgr3e9sn259pcejgrk4ykystcs7v8j6\"> \"UnsignedTx object:\"> [object] { objectType: UnsignedTx addTxInput: function (txId,txIx) addSimpleTxOut: function (destAddr,lovelaceAmount) setFee: function (lovelaceAmount) estimateMinFee: function (protocolParams,numKeyWitnesses,numByronKeyWitnesses,totalRefScriptSize) signWithPaymentKey: function (signingKey) }> \"Estimated fee:\"> 164005n> \"SignedTx object:\"> [object] { objectType: SignedTx alsoSignWithPaymentKey: function (signingKey) txToCbor: function () }> \"Tx CBOR:\"> \"84a300d9010281825820be6efd42a3d7b9a00d09d77a5d41e55ceaf0bd093a8aa8a893ce70d9caafd97800018182581d6082935e44937e8b530f32ce672b5d600d0a286b4e8a52c6555f659b871a00989680021a000280a5a100d9010281825820adfc1c30385916da87db1ba3328f0690a57ebb2a6ac9f6f86b2d97f943adae005840a49259b5977aea523b46f01261fbff93e0899e8700319e11f5ab96b67eb628fca1a233ce2d50ee3227b591b84f27237d920d63974d65728362382f751c4d9400f5f6\""); + await expect(page.locator('#test-output')).toHaveText("> \"Api object:\"> [object] { objectType: cardano-api tx: [object Object] newGrpcConnection: async function (...args) wallet: [object Object] }> \"Bech32 of address:\"> \"addr_test1vp93p9em3regvgylxuvet6fgr3e9sn259pcejgrk4ykystcs7v8j6\"> \"UnsignedTx object:\"> [object] { objectType: UnsignedTx addTxInput: function (txId,txIx) addSimpleTxOut: function (destAddr,lovelaceAmount) appendCertificateToTx: function (certCbor) setFee: function (lovelaceAmount) estimateMinFee: function (protocolParams,numKeyWitnesses,numByronKeyWitnesses,totalRefScriptSize) signWithPaymentKey: function (signingKey) }> \"Estimated fee:\"> 164005n> \"SignedTx object:\"> [object] { objectType: SignedTx alsoSignWithPaymentKey: function (signingKey) txToCbor: function () }> \"Tx CBOR:\"> \"84a300d9010281825820be6efd42a3d7b9a00d09d77a5d41e55ceaf0bd093a8aa8a893ce70d9caafd97800018182581d6082935e44937e8b530f32ce672b5d600d0a286b4e8a52c6555f659b871a00989680021a000280a5a100d9010281825820adfc1c30385916da87db1ba3328f0690a57ebb2a6ac9f6f86b2d97f943adae005840a49259b5977aea523b46f01261fbff93e0899e8700319e11f5ab96b67eb628fca1a233ce2d50ee3227b591b84f27237d920d63974d65728362382f751c4d9400f5f6\""); }); diff --git a/cardano-wasm/lib-wrapper/unsigned-tx.d.ts b/cardano-wasm/lib-wrapper/unsigned-tx.d.ts index 0949e5cdfb..e7d6f57446 100644 --- a/cardano-wasm/lib-wrapper/unsigned-tx.d.ts +++ b/cardano-wasm/lib-wrapper/unsigned-tx.d.ts @@ -27,6 +27,13 @@ declare interface UnsignedTx { */ addSimpleTxOut(destAddr: string, lovelaceAmount: bigint): UnsignedTx; + /** + * Appends a certificate (in CBOR hex string format) to the transaction. + * @param certCbor The certificate in CBOR hex string format. + * @returns The `UnsignedTx` object with the added certificate. + */ + appendCertificateToTx(certCbor: string): UnsignedTx; + /** * Sets the fee for the transaction. * @param lovelaceAmount The fee amount in lovelaces. diff --git a/cardano-wasm/src-lib/Cardano/Wasm/Api/Info.hs b/cardano-wasm/src-lib/Cardano/Wasm/Api/Info.hs index 2da549b401..2a68eee2f7 100644 --- a/cardano-wasm/src-lib/Cardano/Wasm/Api/Info.hs +++ b/cardano-wasm/src-lib/Cardano/Wasm/Api/Info.hs @@ -302,6 +302,16 @@ apiInfo = , methodReturnType = Fluent , methodReturnDoc = "The `UnsignedTx` object with the added output." } + , MethodInfoEntry $ + MethodInfo + { methodName = "appendCertificateToTx" + , methodDoc = "Appends a certificate (in CBOR hex string format) to the transaction." + , methodParams = + [ ParamInfo "certCbor" TSString "The certificate in CBOR hex string format." + ] + , methodReturnType = Fluent + , methodReturnDoc = "The `UnsignedTx` object with the added certificate." + } , MethodInfoEntry $ MethodInfo { methodName = "setFee" diff --git a/cardano-wasm/src-wasm/Cardano/Wasm/Internal/JavaScript/Bridge.hs b/cardano-wasm/src-wasm/Cardano/Wasm/Internal/JavaScript/Bridge.hs index afcfd5d2ce..20a668d661 100644 --- a/cardano-wasm/src-wasm/Cardano/Wasm/Internal/JavaScript/Bridge.hs +++ b/cardano-wasm/src-wasm/Cardano/Wasm/Internal/JavaScript/Bridge.hs @@ -353,6 +353,9 @@ foreign export javascript "addTxInput" foreign export javascript "addSimpleTxOut" addSimpleTxOut :: JSUnsignedTx -> JSString -> JSCoin -> IO JSUnsignedTx +foreign export javascript "appendCertificateToTx" + appendCertificateToTx :: JSUnsignedTx -> JSString -> IO JSUnsignedTx + foreign export javascript "setFee" setFee :: JSUnsignedTx -> JSCoin -> IO JSUnsignedTx @@ -394,6 +397,16 @@ addSimpleTxOut jsUnsignedTx jsDestAddr jsCoin = <*> fromJSVal jsCoin ) +-- | Append a certificate (in CBOR hex string format) to an unsigned transaction. +appendCertificateToTx :: HasCallStack => JSUnsignedTx -> JSString -> IO JSUnsignedTx +appendCertificateToTx jsUnsignedTx jsCertCbor = + toJSVal + =<< join + ( Wasm.appendCertificateToTxImpl + <$> fromJSVal jsUnsignedTx + <*> fromJSVal jsCertCbor + ) + -- | Set the transaction fee for an unsigned transaction. setFee :: HasCallStack => JSUnsignedTx -> JSCoin -> IO JSUnsignedTx setFee jsUnsignedTx jsCoin =