Skip to content

Commit 20b9e9d

Browse files
authored
Merge pull request #953 from IntersectMBO/newtx-and-newexperimentaleratx
Add `newTx` and `newExperimentalEraTx` functions to `cardano-wasm` API
2 parents 1a91cb1 + aad5041 commit 20b9e9d

8 files changed

Lines changed: 91 additions & 13 deletions

File tree

cardano-wasm/examples/basic/example.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async function do_async_work() {
5454
log("Bech32 of address:");
5555
log(bech32Address);
5656

57-
let emptyTx = await api.newConwayTx();
57+
let emptyTx = await api.newTx();
5858
log("UnsignedTx object:");
5959
log(emptyTx);
6060

cardano-wasm/examples/simple-wallet/example.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ async function do_async_work() {
3434
}
3535

3636
async function makeTransaction() {
37-
let tx = await api.newConwayTx();
37+
let tx = await api.newTx();
3838
for (let input of transactionInputs) {
3939
tx = tx.addTxInput(input.txId, input.txIndex);
4040
}

cardano-wasm/js-test/basic-test.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ test('test output matches', async ({ page }) => {
88
// Wait for the test to finish running (we signal this by creating a tag with id "finish-tag" and text "Finished test!")
99
await expect(page.locator('#finish-tag')).toHaveText("Finished test!");
1010
// 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.
11-
await expect(page.locator('#test-output')).toHaveText("> \"Api object:\"> [object] { objectType: cardano-api newConwayTx: async function(...args) newGrpcConnection: async function(...args) generatePaymentWallet: async function(...args) restorePaymentWalletFromSigningKeyBech32: async function(...args) generateTestnetPaymentWallet: async function(...args) restoreTestnetPaymentWalletFromSigningKeyBech32: async function(...args) }> \"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\"");
11+
await expect(page.locator('#test-output')).toHaveText("> \"Api object:\"> [object] { objectType: cardano-api newTx: async function(...args) newExperimentalEraTx: async function(...args) newConwayTx: async function(...args) newGrpcConnection: async function(...args) generatePaymentWallet: async function(...args) restorePaymentWalletFromSigningKeyBech32: async function(...args) generateTestnetPaymentWallet: async function(...args) restoreTestnetPaymentWalletFromSigningKeyBech32: async function(...args) }> \"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\"");
1212
});

cardano-wasm/lib-wrapper/cardano-api.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,19 @@ declare interface CardanoApi {
1616
objectType: string;
1717

1818
/**
19-
* Creates a new Conway-era transaction.
19+
* Create a new unsigned transaction in the current era (currently Conway).
20+
* @returns A promise that resolves to a new `UnsignedTx` object.
21+
*/
22+
newTx(): Promise<UnsignedTx>;
23+
24+
/**
25+
* Create a new unsigned transaction in the current experimental era (currently unavailable).
26+
* @returns A promise that resolves to a new `UnsignedTx` object.
27+
*/
28+
newExperimentalEraTx(): Promise<UnsignedTx>;
29+
30+
/**
31+
* Create a new unsigned transaction in the Conway era.
2032
* @returns A promise that resolves to a new `UnsignedTx` object.
2133
*/
2234
newConwayTx(): Promise<UnsignedTx>;

cardano-wasm/src/Cardano/Wasm/Internal/Api/Info.hs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ module Cardano.Wasm.Internal.Api.Info
1212
)
1313
where
1414

15+
import Cardano.Api (pretty)
16+
17+
import Cardano.Wasm.Internal.Api.Tx (UnsignedTxObject (..), newExperimentalEraTxImpl, newTxImpl)
18+
1519
import Data.Aeson qualified as Aeson
1620
import Data.Text qualified as Text
1721
import Text.Casing (fromHumps, toKebab)
@@ -150,6 +154,13 @@ instance Aeson.ToJSON ApiInfo where
150154
, "initialiseFunctionReturnDoc" Aeson..= initRetDoc
151155
]
152156

157+
-- | Get a comment about the era for unsigned transaction creation methods.
158+
getEraCommentForUnsignedTx :: Maybe UnsignedTxObject -> String
159+
getEraCommentForUnsignedTx utxMonad =
160+
case utxMonad of
161+
Just (UnsignedTxObject era _) -> "(currently " ++ show (pretty era) ++ ")"
162+
Nothing -> "(currently unavailable)"
163+
153164
-- | Provides metadata about the "virtual objects" and their methods.
154165
-- This is intended to help generate JavaScript wrappers.
155166
apiInfo :: ApiInfo
@@ -327,8 +338,28 @@ apiInfo =
327338
, virtualObjectDoc = "The main Cardano API object with static methods."
328339
, virtualObjectMethods =
329340
[ MethodInfo
341+
{ methodName = "newTx"
342+
, methodDoc =
343+
"Create a new unsigned transaction in the current era "
344+
++ getEraCommentForUnsignedTx (Just newTxImpl)
345+
++ "."
346+
, methodParams = []
347+
, methodReturnType = NewObject (virtualObjectName unsignedTxObj)
348+
, methodReturnDoc = "A promise that resolves to a new `UnsignedTx` object."
349+
}
350+
, MethodInfo
351+
{ methodName = "newExperimentalEraTx"
352+
, methodDoc =
353+
"Create a new unsigned transaction in the current experimental era "
354+
++ getEraCommentForUnsignedTx newExperimentalEraTxImpl
355+
++ "."
356+
, methodParams = []
357+
, methodReturnType = NewObject (virtualObjectName unsignedTxObj)
358+
, methodReturnDoc = "A promise that resolves to a new `UnsignedTx` object."
359+
}
360+
, MethodInfo
330361
{ methodName = "newConwayTx"
331-
, methodDoc = "Creates a new Conway-era transaction."
362+
, methodDoc = "Create a new unsigned transaction in the Conway era."
332363
, methodParams = []
333364
, methodReturnType = NewObject (virtualObjectName unsignedTxObj)
334365
, methodReturnDoc = "A promise that resolves to a new `UnsignedTx` object."

cardano-wasm/src/Cardano/Wasm/Internal/Api/Tx.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
module Cardano.Wasm.Internal.Api.Tx
1111
( UnsignedTxObject (..)
1212
, ProtocolParamsJSON (..)
13+
, newTxImpl
14+
, newExperimentalEraTxImpl
1315
, newConwayTxImpl
1416
, addTxInputImpl
1517
, addSimpleTxOutImpl
@@ -30,7 +32,7 @@ import Cardano.Api.Plutus qualified as Shelley
3032
import Cardano.Api.Tx qualified as TxBody
3133

3234
import Cardano.Ledger.Api qualified as Ledger
33-
import Cardano.Wasm.Internal.ExceptionHandling (justOrError, rightOrError, toMonadFail)
35+
import Cardano.Wasm.Internal.ExceptionHandling (justOrError, rightOrError, throwError, toMonadFail)
3436

3537
import Control.Monad.Catch (MonadThrow)
3638
import Data.Aeson (ToJSON (toJSON), (.=))
@@ -75,6 +77,14 @@ instance FromJSON UnsignedTxObject where
7577
era
7678
<$> toMonadFail (rightOrError $ Api.deserialiseFromRawBytesHex $ Text.encodeUtf8 tx)
7779

80+
-- | Create a new unsigned transaction object for making a transaction in the current era.
81+
newTxImpl :: UnsignedTxObject
82+
newTxImpl = newConwayTxImpl
83+
84+
-- | Create a new unsigned transaction object for making a transaction in the current experimental era.
85+
newExperimentalEraTxImpl :: (HasCallStack, MonadThrow m) => m UnsignedTxObject
86+
newExperimentalEraTxImpl = throwError "newExperimentalEraTxImpl: No experimental era available"
87+
7888
-- | Create a new unsigned transaction object for making a Conway era transaction.
7989
newConwayTxImpl :: UnsignedTxObject
8090
newConwayTxImpl = UnsignedTxObject Exp.ConwayEra (Exp.UnsignedTx (Ledger.mkBasicTx Ledger.mkBasicTxBody))

cardano-wasm/src/Cardano/Wasm/Internal/ExceptionHandling.hs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,42 @@ module Cardano.Wasm.Internal.ExceptionHandling where
55

66
import Control.Exception (Exception, displayException)
77
import Control.Monad.Catch (MonadThrow (..))
8-
import GHC.Exception (CallStack, prettyCallStack)
8+
import GHC.Exception (prettyCallStack)
99
import GHC.Stack (HasCallStack, callStack, withFrozenCallStack)
1010

11-
data ExpectedJustException = HasCallStack => ExpectedJustException CallStack String
11+
data ExpectedJustException = HasCallStack => ExpectedJustException String
1212

1313
instance Show ExpectedJustException where
1414
show :: ExpectedJustException -> String
15-
show (ExpectedJustException cs msg) = "Expected Just, got Nothing: " ++ msg ++ "\n" ++ prettyCallStack cs
15+
show (ExpectedJustException msg) = "Expected Just, got Nothing: " ++ msg ++ "\n" ++ prettyCallStack callStack
1616

1717
instance Exception ExpectedJustException
1818

19-
data ExpectedRightException = HasCallStack => ExpectedRightException CallStack String
19+
data ExpectedRightException = HasCallStack => ExpectedRightException String
2020

2121
instance Show ExpectedRightException where
2222
show :: ExpectedRightException -> String
23-
show (ExpectedRightException cs msg) = "Expected Right, got Left: " ++ msg ++ "\n" ++ prettyCallStack cs
23+
show (ExpectedRightException msg) = "Expected Right, got Left: " ++ msg ++ "\n" ++ prettyCallStack callStack
2424

2525
instance Exception ExpectedRightException
2626

27+
data CustomException = HasCallStack => CustomException String
28+
29+
instance Show CustomException where
30+
show :: CustomException -> String
31+
show (CustomException msg) = "Custom exception: " ++ msg ++ "\n" ++ prettyCallStack callStack
32+
33+
instance Exception CustomException
34+
35+
throwError :: (HasCallStack, MonadThrow m) => String -> m a
36+
throwError e = withFrozenCallStack $ throwM $ CustomException e
37+
2738
justOrError :: (HasCallStack, MonadThrow m) => String -> Maybe a -> m a
28-
justOrError e Nothing = withFrozenCallStack $ throwM $ ExpectedJustException callStack e
39+
justOrError e Nothing = withFrozenCallStack $ throwM $ ExpectedJustException e
2940
justOrError _ (Just a) = return a
3041

3142
rightOrError :: (HasCallStack, MonadThrow m, Show e) => Either e a -> m a
32-
rightOrError (Left e) = withFrozenCallStack $ throwM $ ExpectedRightException callStack $ show e
43+
rightOrError (Left e) = withFrozenCallStack $ throwM $ ExpectedRightException $ show e
3344
rightOrError (Right a) = return a
3445

3546
-- | Convert an 'Either' value to a 'MonadFail' monad. This can be useful for converting

cardano-wasm/src/Cardano/Wasm/Internal/JavaScript/Bridge.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,12 @@ getBase16ForVerificationKeyHash jsWallet =
272272

273273
-- * UnsignedTxObject
274274

275+
foreign export javascript "newTx"
276+
newTx :: IO JSUnsignedTx
277+
278+
foreign export javascript "newExperimentalEraTx"
279+
newExperimentalEraTx :: IO JSUnsignedTx
280+
275281
foreign export javascript "newConwayTx"
276282
newConwayTx :: IO JSUnsignedTx
277283

@@ -290,6 +296,14 @@ foreign export javascript "estimateMinFee"
290296
foreign export javascript "signWithPaymentKey"
291297
signWithPaymentKey :: JSUnsignedTx -> JSSigningKey -> IO JSSignedTx
292298

299+
-- | Create a new unsigned transaction.
300+
newTx :: HasCallStack => IO JSUnsignedTx
301+
newTx = toJSVal Wasm.newTxImpl
302+
303+
-- | Create a new experimental era unsigned transaction.
304+
newExperimentalEraTx :: HasCallStack => IO JSUnsignedTx
305+
newExperimentalEraTx = toJSVal =<< Wasm.newExperimentalEraTxImpl
306+
293307
-- | Create a new Conway era unsigned transaction.
294308
newConwayTx :: HasCallStack => IO JSUnsignedTx
295309
newConwayTx = toJSVal Wasm.newConwayTxImpl

0 commit comments

Comments
 (0)