Skip to content

Commit ff61025

Browse files
authored
Merge pull request #1003 from IntersectMBO/group-methods
Group static methods in `cardano-wasm` API
2 parents 4cdb67f + 4ec72e2 commit ff61025

File tree

12 files changed

+584
-365
lines changed

12 files changed

+584
-365
lines changed

cardano-wasm/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,16 @@ To work around that, disable build concurrency:
253253
wasm32-wasi-cabal build cardano-wasm -j1 --ghc-options="-j1" --no-semaphore
254254
```
255255

256+
# Documentation
257+
258+
You can find the generated typedoc documentation for the version of `cardano-wasm` in `master` branch [here](https://cardano-api.cardano.intersectmbo.org/cardano-wasm/typedoc/).
259+
260+
Or you can generate it using nix by writing:
261+
262+
```bash
263+
nix build .#wasm-typedoc
264+
```
265+
256266
# Examples
257267

258268
You can find examples of how to use the `cardano-wasm` library in the [examples](./examples) subfolder.

cardano-wasm/examples/basic/example.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ async function do_async_work() {
4848

4949
let PREVIEW_MAGIC_NUMBER = 2;
5050
let secretKey = "addr_sk1648253w4tf6fv5fk28dc7crsjsaw7d9ymhztd4favg3cwkhz7x8sl5u3ms";
51-
let wallet = await api.restoreTestnetPaymentWalletFromSigningKeyBech32(PREVIEW_MAGIC_NUMBER, secretKey);
51+
let wallet = await api.wallet.testnet.restoreTestnetPaymentWalletFromSigningKeyBech32(PREVIEW_MAGIC_NUMBER, secretKey);
5252
let bech32Address = await wallet.getAddressBech32();
5353

5454
log("Bech32 of address:");
5555
log(bech32Address);
5656

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

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async function do_async_work() {
1111

1212
// State
1313
let showPrivateKey = false;
14-
let wallet = await api.generateTestnetPaymentWallet(42);
14+
let wallet = await api.wallet.testnet.generateTestnetPaymentWallet(42);
1515
let transactionInputs = [];
1616
let transactionOutputs = [];
1717

@@ -34,7 +34,7 @@ async function do_async_work() {
3434
}
3535

3636
async function makeTransaction() {
37-
let tx = await api.newTx();
37+
let tx = await api.tx.newTx();
3838
for (let input of transactionInputs) {
3939
tx = tx.addTxInput(input.txId, input.txIndex);
4040
}
@@ -55,7 +55,7 @@ async function do_async_work() {
5555
let pki = document.getElementById("private-key-input")
5656
if (showPrivateKey) {
5757
// @ts-ignore
58-
pki.value = await wallet.getBech32ForSigningKey();
58+
pki.value = await wallet.getBech32ForPaymentSigningKey();
5959
// @ts-ignore
6060
pki.disabled = false;
6161
// @ts-ignore
@@ -188,7 +188,7 @@ async function do_async_work() {
188188

189189
// Callbacks
190190
async function generateAddress() {
191-
wallet = await api.generateTestnetPaymentWallet(TESTNET_MAGIC);
191+
wallet = await api.wallet.testnet.generateTestnetPaymentWallet(TESTNET_MAGIC);
192192
await refresh();
193193
}
194194

@@ -239,7 +239,7 @@ async function do_async_work() {
239239

240240
async function submitTransaction() {
241241
let tx = await makeTransaction();
242-
let signingKey = await wallet.getBech32ForSigningKey();
242+
let signingKey = await wallet.getBech32ForPaymentSigningKey();
243243
let signedTx = await tx.signWithPaymentKey(signingKey);
244244

245245
await grpcApi.submitTx(await signedTx.txToCbor()).then((txId) => {

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 newTx: async function(...args) newExperimentalEraTx: async function(...args) newConwayTx: async function(...args) newGrpcConnection: async function(...args) generatePaymentWallet: async function(...args) generateStakeWallet: async function(...args) restorePaymentWalletFromSigningKeyBech32: async function(...args) restoreStakeWalletFromSigningKeyBech32: async function(...args) generateTestnetPaymentWallet: async function(...args) generateTestnetStakeWallet: async function(...args) restoreTestnetPaymentWalletFromSigningKeyBech32: async function(...args) restoreTestnetStakeWalletFromSigningKeyBech32: 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 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\"");
1212
});

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

Lines changed: 90 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,27 @@ declare interface CardanoApi {
1616
objectType: string;
1717

1818
/**
19-
* Create a new unsigned transaction in the current era (currently Conway).
20-
* @returns A promise that resolves to a new `UnsignedTx` object.
19+
* Methods for creating unsigned transactions.
2120
*/
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.
32-
* @returns A promise that resolves to a new `UnsignedTx` object.
33-
*/
34-
newConwayTx(): Promise<UnsignedTx>;
21+
tx: {
22+
/**
23+
* Create a new unsigned transaction in the current era (currently Conway).
24+
* @returns A promise that resolves to a new `UnsignedTx` object.
25+
*/
26+
newTx(): Promise<UnsignedTx>;
27+
28+
/**
29+
* Create a new unsigned transaction in the current experimental era (currently unavailable).
30+
* @returns A promise that resolves to a new `UnsignedTx` object.
31+
*/
32+
newExperimentalEraTx(): Promise<UnsignedTx>;
33+
34+
/**
35+
* Create a new unsigned transaction in the Conway era.
36+
* @returns A promise that resolves to a new `UnsignedTx` object.
37+
*/
38+
newConwayTx(): Promise<UnsignedTx>;
39+
}
3540

3641
/**
3742
* Create a new client connection for communicating with a Cardano node through gRPC-web.
@@ -41,62 +46,77 @@ declare interface CardanoApi {
4146
newGrpcConnection(webGrpcUrl: string): Promise<GrpcConnection>;
4247

4348
/**
44-
* Generate a simple payment wallet for mainnet.
45-
* @returns A promise that resolves to a new `Wallet` object.
46-
*/
47-
generatePaymentWallet(): Promise<Wallet>;
48-
49-
/**
50-
* Generate a stake wallet for mainnet.
51-
* @returns A promise that resolves to a new `Wallet` object.
52-
*/
53-
generateStakeWallet(): Promise<Wallet>;
54-
55-
/**
56-
* Restore a mainnet payment wallet from a Bech32 encoded signing key.
57-
* @param signingKeyBech32 The Bech32 encoded signing key.
58-
* @returns A promise that resolves to a new `Wallet` object.
59-
*/
60-
restorePaymentWalletFromSigningKeyBech32(signingKeyBech32: string): Promise<Wallet>;
61-
62-
/**
63-
* Restore a mainnet stake wallet from Bech32 encoded signing keys.
64-
* @param paymentSigningKeyBech32 The Bech32 encoded payment signing key.
65-
* @param stakeSigningKeyBech32 The Bech32 encoded stake signing key.
66-
* @returns A promise that resolves to a new `Wallet` object.
67-
*/
68-
restoreStakeWalletFromSigningKeyBech32(paymentSigningKeyBech32: string, stakeSigningKeyBech32: string): Promise<Wallet>;
69-
70-
/**
71-
* Generate a simple payment wallet for testnet, given the testnet's network magic.
72-
* @param networkMagic The network magic for the testnet.
73-
* @returns A promise that resolves to a new `Wallet` object.
74-
*/
75-
generateTestnetPaymentWallet(networkMagic: number): Promise<Wallet>;
76-
77-
/**
78-
* Generate a stake wallet for testnet, given the testnet's network magic.
79-
* @param networkMagic The network magic for the testnet.
80-
* @returns A promise that resolves to a new `Wallet` object.
81-
*/
82-
generateTestnetStakeWallet(networkMagic: number): Promise<Wallet>;
83-
84-
/**
85-
* Restore a testnet payment wallet from a Bech32 encoded signing key.
86-
* @param networkMagic The network magic for the testnet.
87-
* @param signingKeyBech32 The Bech32 encoded signing key.
88-
* @returns A promise that resolves to a new `Wallet` object.
89-
*/
90-
restoreTestnetPaymentWalletFromSigningKeyBech32(networkMagic: number, signingKeyBech32: string): Promise<Wallet>;
91-
92-
/**
93-
* Restore a testnet stake wallet from Bech32 encoded signing keys.
94-
* @param networkMagic The network magic for the testnet.
95-
* @param paymentSigningKeyBech32 The Bech32 encoded payment signing key.
96-
* @param stakeSigningKeyBech32 The Bech32 encoded stake signing key.
97-
* @returns A promise that resolves to a new `Wallet` object.
49+
* Methods for generating and restoring wallets.
9850
*/
99-
restoreTestnetStakeWalletFromSigningKeyBech32(networkMagic: number, paymentSigningKeyBech32: string, stakeSigningKeyBech32: string): Promise<Wallet>;
51+
wallet: {
52+
/**
53+
* Methods for mainnet wallets.
54+
*/
55+
mainnet: {
56+
/**
57+
* Generate a simple payment wallet for mainnet.
58+
* @returns A promise that resolves to a new `Wallet` object.
59+
*/
60+
generatePaymentWallet(): Promise<Wallet>;
61+
62+
/**
63+
* Generate a stake wallet for mainnet.
64+
* @returns A promise that resolves to a new `Wallet` object.
65+
*/
66+
generateStakeWallet(): Promise<Wallet>;
67+
68+
/**
69+
* Restore a mainnet payment wallet from a Bech32 encoded signing key.
70+
* @param signingKeyBech32 The Bech32 encoded signing key.
71+
* @returns A promise that resolves to a new `Wallet` object.
72+
*/
73+
restorePaymentWalletFromSigningKeyBech32(signingKeyBech32: string): Promise<Wallet>;
74+
75+
/**
76+
* Restore a mainnet stake wallet from Bech32 encoded signing keys.
77+
* @param paymentSigningKeyBech32 The Bech32 encoded payment signing key.
78+
* @param stakeSigningKeyBech32 The Bech32 encoded stake signing key.
79+
* @returns A promise that resolves to a new `Wallet` object.
80+
*/
81+
restoreStakeWalletFromSigningKeyBech32(paymentSigningKeyBech32: string, stakeSigningKeyBech32: string): Promise<Wallet>;
82+
}
83+
84+
/**
85+
* Methods for wallets in other networks.
86+
*/
87+
testnet: {
88+
/**
89+
* Generate a simple payment wallet for testnet, given the testnet's network magic.
90+
* @param networkMagic The network magic for the testnet.
91+
* @returns A promise that resolves to a new `Wallet` object.
92+
*/
93+
generateTestnetPaymentWallet(networkMagic: number): Promise<Wallet>;
94+
95+
/**
96+
* Generate a stake wallet for testnet, given the testnet's network magic.
97+
* @param networkMagic The network magic for the testnet.
98+
* @returns A promise that resolves to a new `Wallet` object.
99+
*/
100+
generateTestnetStakeWallet(networkMagic: number): Promise<Wallet>;
101+
102+
/**
103+
* Restore a testnet payment wallet from a Bech32 encoded signing key.
104+
* @param networkMagic The network magic for the testnet.
105+
* @param signingKeyBech32 The Bech32 encoded signing key.
106+
* @returns A promise that resolves to a new `Wallet` object.
107+
*/
108+
restoreTestnetPaymentWalletFromSigningKeyBech32(networkMagic: number, signingKeyBech32: string): Promise<Wallet>;
109+
110+
/**
111+
* Restore a testnet stake wallet from Bech32 encoded signing keys.
112+
* @param networkMagic The network magic for the testnet.
113+
* @param paymentSigningKeyBech32 The Bech32 encoded payment signing key.
114+
* @param stakeSigningKeyBech32 The Bech32 encoded stake signing key.
115+
* @returns A promise that resolves to a new `Wallet` object.
116+
*/
117+
restoreTestnetStakeWalletFromSigningKeyBech32(networkMagic: number, paymentSigningKeyBech32: string, stakeSigningKeyBech32: string): Promise<Wallet>;
118+
}
119+
}
100120
}
101121

102122
/**

cardano-wasm/lib-wrapper/main.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
2222
/**
2323
* Convert Base64 to Base16 encoding
2424
*/
25-
base64ToHex: function(base64) {
25+
base64ToHex: function (base64) {
2626
if (typeof atob === 'function') {
2727
const binary = atob(base64);
2828
return [...binary].reduce((hex, char) => {
@@ -88,19 +88,32 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
8888
const apiInfo = await instance.exports.getApiInfo();
8989
let makers = {};
9090
let cardanoApi = { objectType: "cardano-api" };
91+
9192
// Create maker functions for each virtual object type
93+
94+
function populateMethodOrGroup(methodPopulator, methodOrGroup, target) {
95+
if (methodOrGroup.type === "method") {
96+
methodPopulator(methodOrGroup.method, target);
97+
} else if (methodOrGroup.type === "group") {
98+
let group = methodOrGroup.group;
99+
target = target[group.name] = {};
100+
group.methods.forEach(methodOrGroup =>
101+
populateMethodOrGroup(methodPopulator, methodOrGroup, target)
102+
);
103+
}
104+
}
105+
92106
apiInfo.virtualObjects.forEach(vo => {
93-
makers[vo.objectName] = function(initialHaskellValuePromise) {
107+
makers[vo.objectName] = function (initialHaskellValuePromise) {
94108
// currentHaskellValueProvider is a function that returns a Promise for the Haskell value
95109
// It starts with the initial value promise and fluent methods accumulate transformations
96110
let currentHaskellValueProvider = () => initialHaskellValuePromise;
97-
let jsObject = { objectType: vo.objectName };
98111

99-
vo.methods.forEach(method => {
112+
function populateDynamicMethod(method, target) {
100113
if (method.return.type === "fluent") {
101114
// Fluent methods are synchronous and update the provider
102115
// A fluent method is one that returns the same object type
103-
jsObject[method.name] = fixateArgs(method.params, function(...args) {
116+
target[method.name] = fixateArgs(method.params, function (...args) {
104117
const previousProvider = currentHaskellValueProvider;
105118
// We update the provider so that it resolves the previous provider and chains the next call
106119
currentHaskellValueProvider = async () => {
@@ -111,7 +124,7 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
111124
});
112125
} else {
113126
// Non-fluent methods (newObject or other) are async and apply the accumulated method calls
114-
jsObject[method.name] = fixateArgs(method.params, async function(...args) {
127+
target[method.name] = fixateArgs(method.params, async function (...args) {
115128
const haskellValue = await currentHaskellValueProvider(); // Resolve accumulated method calls
116129
const resultPromise = instance.exports[method.name](haskellValue, ...args); // Call the non-fluent method
117130

@@ -122,14 +135,27 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
122135
}
123136
});
124137
}
138+
}
139+
140+
let jsObject = { objectType: vo.objectName };
141+
142+
vo.methods.forEach(method => {
143+
populateMethodOrGroup(populateDynamicMethod, method, jsObject);
125144
});
126145
return jsObject;
127146
};
128147
});
129148

130149
// Populate the main API object with static methods
131-
apiInfo.mainObject.methods.forEach(method => {
132-
cardanoApi[method.name] = async function(...args) {
150+
151+
function populateStaticMethod(method, target) {
152+
target[method.name] = async function (...args) {
153+
if (method.group) {
154+
if (!target[method.group]) {
155+
target[method.group] = {};
156+
}
157+
target = target[method.group];
158+
}
133159
const resultPromise = instance.exports[method.name](...args);
134160

135161
if (method.return.type === "newObject") { // Create a new object
@@ -138,6 +164,10 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
138164
return resultPromise;
139165
}
140166
};
167+
}
168+
169+
apiInfo.mainObject.methods.forEach(methodOrGroup => {
170+
populateMethodOrGroup(populateStaticMethod, methodOrGroup, cardanoApi);
141171
});
142172

143173
return cardanoApi;

cardano-wasm/npm-wrapper/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Create an `index.js` file:
3939

4040
// 3. Now you can use the API to perform Cardano operations.
4141
// For example, let's create a new transaction body.
42-
const tx = await api.newTx();
42+
const tx = await api.tx.newTx();
4343
console.log("New Transaction Body Created:", tx);
4444

4545
// You can now build upon the 'tx' object to add inputs, outputs, etc.

cardano-wasm/npm-wrapper/api.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ describe('Cardano API', () => {
2323
const outputAddress = "addr_test1vzpfxhjyjdlgk5c0xt8xw26avqxs52rtf69993j4tajehpcue4v2v";
2424

2525
// Restore wallet and verify the address
26-
const wallet = await api.restoreTestnetPaymentWalletFromSigningKeyBech32(PREVIEW_MAGIC_NUMBER, secretKey);
26+
const wallet = await api.wallet.testnet.restoreTestnetPaymentWalletFromSigningKeyBech32(PREVIEW_MAGIC_NUMBER, secretKey);
27+
2728
const bech32Address = await wallet.getAddressBech32();
2829
expect(bech32Address).toBe(expectedAddress);
2930

3031
// Create a new transaction
31-
const emptyTx = await api.newTx();
32+
const emptyTx = await api.tx.newTx();
3233
expect(emptyTx).toBeDefined();
3334

3435
// Add inputs and outputs

0 commit comments

Comments
 (0)