Skip to content

Commit ebf25e7

Browse files
authoredDec 8, 2023
Merge pull request #54 from input-output-hk/PLT-8261
Open Roles & Clean buildCreateContractTx Request
2 parents 03f231f + 09fc3cd commit ebf25e7

File tree

34 files changed

+1062
-279
lines changed

34 files changed

+1062
-279
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### @marlowe.io/runtime-rest-client
2+
3+
- `createContract` Endpoint has been renamed to `buildCreateContractTx` ([PR#54](https://github.com/input-output-hk/marlowe-ts-sdk/pull/54))
4+
- `buildCreateContractTx` is 1-1 parity with REST API request-wise ([PR#54](https://github.com/input-output-hk/marlowe-ts-sdk/pull/54))
5+
6+
### @marlowe.io/runtime-lifecycle
7+
8+
- `createContract` is complete request-wise for creating non-merkleized contracts ([PR#54](https://github.com/input-output-hk/marlowe-ts-sdk/pull/54))

‎examples/rest-client-flow/index.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ <h2>Request</h2>
7676
>
7777
<br />
7878
<input
79-
id="createContract"
79+
id="buildCreateContractTx"
8080
type="button"
81-
value="Create Contract"
81+
value="Build Create Contract Tx"
8282
class="endpoint"
8383
/>
8484
POSTs a new contract
8585
<a
86-
href="https://input-output-hk.github.io/marlowe-ts-sdk/interfaces/_marlowe_io_runtime_rest_client.index.RestClient.html#createContract"
86+
href="https://input-output-hk.github.io/marlowe-ts-sdk/interfaces/_marlowe_io_runtime_rest_client.index.RestClient.html#buildCreateContractTx"
8787
>/contracts</a
8888
>
8989
<br />

‎examples/run-lite/index.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ <h2>Console</h2>
108108
walletName,
109109
});
110110

111-
const contractId = await runtime.contracts.createContract({ contract });
111+
const contractId = await runtime.contracts.createContract({
112+
contract: contract,
113+
});
112114
log("Contract created with id: " + contractId);
113115
setContractIdIndicator(contractId);
114116
}

‎examples/survey-workshop/participant/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ async function createContract(
124124

125125
const lifecycle = await H.getLifecycle();
126126
const [contractId] = await lifecycle.contracts.createContract({
127-
contract,
127+
contract: contract,
128128
tags: { MarloweSurvey: "test 1" },
129129
});
130130

‎jsdelivr-npm-importmap.js

+41-72
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/adapter/src/codec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ import JSONbigint from "json-bigint";
55

66
export type DecodingError = string[];
77

8+
/**
9+
* ```ts
10+
* try {
11+
* myRuntimeEndpoint(myRequest);
12+
* } catch (error){
13+
* if(error instanceOf UnexpectedRuntimeResponse) {
14+
* console.error("The Runtime answered an unexpected message, please contact our desk support",error)
15+
* } else {
16+
* console.error("another type of error",error)
17+
* }
18+
* }
19+
* ```
20+
*/
21+
export class UnexpectedRuntimeResponse extends Error {
22+
public type = "UnexpectedRuntimeResponse" as const;
23+
constructor(message: string) {
24+
super(message);
25+
}
26+
}
27+
828
export const MarloweJSON = JSONbigint({
929
alwaysParseAsBig: true,
1030
useNativeBigInt: true,
+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as t from "io-ts/lib/index.js";
22

3-
// TODO: This should be DELETED as there is a newtype for this in runtime-core,
4-
// but a preliminary change broke the build with weird type errors
3+
// TODO: This should be replaced by a Branded Version available in the Runtime Rest Client Package,
54
export type AddressBech32 = string;
65
export const AddressBech32 = t.string;

‎packages/language/core/v1/src/guards.ts

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
@packageDocumentation
1414
*/
1515

16+
export { PolicyIdGuard as PolicyId } from "./policyId.js";
17+
1618
export {
1719
ActionGuard as Action,
1820
DepositGuard as Deposit,
@@ -58,6 +60,7 @@ export {
5860

5961
export {
6062
RoleGuard as Role,
63+
RoleNameGuard as RoleName,
6164
PartyGuard as Party,
6265
AddressGuard as Address,
6366
} from "./participants.js";

‎packages/language/core/v1/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export {
5555
MerkleizedInput,
5656
} from "./inputs.js";
5757

58-
export { role, Party, Address, Role } from "./participants.js";
58+
export { role, Party, Address, Role, RoleName } from "./participants.js";
5959

6060
export { Payee, PayeeAccount, PayeeParty, AccountId } from "./payee.js";
6161

‎packages/language/core/v1/src/participants.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export interface Address {
2929
*/
3030
export const AddressGuard: t.Type<Address> = t.type({ address: AddressBech32 });
3131

32-
type RoleName = string;
33-
const RoleNameGuard: t.Type<RoleName> = t.string;
32+
export type RoleName = string;
33+
export const RoleNameGuard: t.Type<RoleName> = t.string;
3434

3535
/**
3636
* Search [[lower-name-builders]]

‎packages/language/core/v1/src/policyId.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ export type PolicyId = string;
88
/**
99
* @category Token
1010
*/
11-
export const PolicyId = t.string;
11+
export const PolicyIdGuard = t.string;

‎packages/language/core/v1/src/token.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Sort, strCmp } from "@marlowe.io/adapter/assoc-map";
22
import * as t from "io-ts/lib/index.js";
3-
import { PolicyId } from "./policyId.js";
3+
import { PolicyId, PolicyIdGuard } from "./policyId.js";
44
/**
55
* @see {@link @marlowe.io/language-core-v1!index.Token}.
66
* @category Token
@@ -26,7 +26,7 @@ export interface Token {
2626
* @category Token
2727
*/
2828
export const TokenGuard: t.Type<Token> = t.type({
29-
currency_symbol: PolicyId,
29+
currency_symbol: PolicyIdGuard,
3030
token_name: TokenNameGuard,
3131
});
3232

‎packages/runtime/client/rest/package.json

+10-1
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,21 @@
3636
"require": "./dist/bundled/cjs/transaction.cjs",
3737
"types": "./dist/esm/contract/transaction/index.d.ts"
3838
},
39+
"./payout": {
40+
"import": "./dist/esm/payout/index.js",
41+
"require": "./dist/bundled/cjs/payout.cjs",
42+
"types": "./dist/esm/payout/index.d.ts"
43+
},
3944
"./withdrawal": {
4045
"import": "./dist/esm/withdrawal/index.js",
4146
"require": "./dist/bundled/cjs/withdrawal.cjs",
4247
"types": "./dist/esm/withdrawal/index.d.ts"
4348
},
44-
"./contract/*": "./dist/esm/contract/*.js"
49+
"./contract": {
50+
"import": "./dist/esm/contract/index.js",
51+
"require": "./dist/bundled/cjs/contract.cjs",
52+
"types": "./dist/esm/contract/index.d.ts"
53+
}
4554
},
4655
"dependencies": {
4756
"@marlowe.io/adapter": "0.3.0-beta-rc1",

‎packages/runtime/client/rest/src/contract/details.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import { Contract, MarloweState } from "@marlowe.io/language-core-v1";
44
import * as G from "@marlowe.io/language-core-v1/guards";
55
import { MarloweVersion } from "@marlowe.io/language-core-v1/version";
66
import { ContractIdGuard } from "@marlowe.io/runtime-core";
7-
87
import { TxStatus } from "./transaction/status.js";
98

10-
import { RoleName } from "./role.js";
119
import {
1210
TxOutRef,
1311
BlockHeaderGuard,
@@ -34,21 +32,23 @@ export const Payout = t.type({
3432
*/
3533
payoutId: TxOutRef,
3634
/**
37-
* The {@link RoleName} of the participant that has the unclaimed Payout.
35+
* The {@link @marlowe.io/language-core-v1!index.RoleName | Role Name} of the participant that has the unclaimed Payout.
3836
*/
39-
role: RoleName,
37+
role: G.RoleName,
4038
});
4139

4240
/**
43-
* Represents the response of the {@link index.RestClient#getContractById | Get contract by id } endpoint
41+
* Represents the response of the {@link index.RestClient#getContractById | Get Contract By Id } endpoint
4442
* @see The {@link ContractDetails:var | dynamic validator} for this type.
4543
* @interface
44+
* @category Endpoint : Get Contract By Id
4645
*/
4746
export interface ContractDetails extends t.TypeOf<typeof ContractDetails> {}
4847

4948
/**
5049
* This is a {@link !io-ts-usage | Dynamic type validator} for the {@link ContractDetails:type}.
5150
* @category Validator
51+
* @category Endpoint : Get Contract By Id
5252
*/
5353
// DISCUSSION : Tags are missing in the ts-sdk and available in the REST API
5454
export const ContractDetails = t.type({

‎packages/runtime/client/rest/src/contract/endpoints/collection.ts

+298-37
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* This module offers {@link !io-ts-usage | dynamic type guards} for JSON schemas as specified in Runtime Rest API
3+
```
4+
import * as G from "@marlowe/language-core-v1/guards"
5+
const jsonObject = JSON.parse(fileContents)
6+
7+
if (G.Contract.is(jsonObject)) {
8+
// The jsonObject respects the JSON schema for Contract
9+
} else {
10+
// The jsonObject does not respect the JSON schema for Contract
11+
}
12+
```
13+
@packageDocumentation
14+
*/
15+
16+
export {
17+
ClosedRoleGuard as ClosedRole,
18+
OpenRoleGuard as OpenRole,
19+
OpennessGuard as Openess,
20+
UsePolicyWithClosedRoleTokensGuard as UsePolicyWithClosedRoleTokens,
21+
UsePolicyWithOpenRoleTokensGuard as UsePolicyWithOpenRoleTokens,
22+
TokenMetadataFileGuard as TokenMetadataFile,
23+
TokenMetadataGuard as TokenMetadata,
24+
RoleTokenConfigurationGuard as RoleTokenConfiguration,
25+
RolesConfigurationGuard as RolesConfiguration,
26+
AddressBech32Guard as AddressBech32,
27+
} from "./rolesConfigurations.js";

‎packages/runtime/client/rest/src/contract/header.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { TxStatus } from "./transaction/status.js";
2222
* Use {@link index.RestClient#getContractById} to get full contract details
2323
*
2424
* @see The {@link https://github.com/input-output-hk/marlowe-cardano/blob/b39fe3c3ed67d41cdea6d45700093e7ffa4fad62/marlowe-runtime-web/src/Language/Marlowe/Runtime/Web/Types.hs#L502 | The backend definition } of this type
25-
* @category GetContractsResponse
25+
* @category Endpoint : Get Contracts
2626
*/
2727
export interface ContractHeader {
2828
/**
@@ -58,7 +58,7 @@ export interface ContractHeader {
5858
/**
5959
* This is a {@link !io-ts-usage | Dynamic type validator} for a {@link ContractHeaderGuard:type}.
6060
* @category Validator
61-
* @category GetContractsResponse
61+
* @category Endpoint : Get Contracts
6262
* @hidden
6363
*/
6464
export const ContractHeaderGuard = t.type({

‎packages/runtime/client/rest/src/contract/index.ts

+34-3
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,53 @@
22
* ```ts
33
* import * as C from "@marlowe.io/runtime-rest-client/contract";
44
*```
5+
* This package contains all the implementation and details related to
6+
* endpoints under the URI `/contracts/...` :
7+
* - {@link index.RestClient#buildCreateContractTx | Build Create Contract Tx }
8+
* - {@link index.RestClient#getContracts | Get contracts }
9+
* - {@link index.RestClient#getContractById | Get Contract By Id }
10+
511
* @packageDocumentation
612
*/
713

814
export { ContractHeader } from "./header.js";
915
export { ContractDetails } from "./details.js";
10-
export { RolesConfig } from "./role.js";
16+
export {
17+
useMintedRoles,
18+
mintRole,
19+
AddressBech32Brand,
20+
AddressBech32,
21+
openRole,
22+
ClosedRole,
23+
OpenRole,
24+
Openness,
25+
UsePolicyWithClosedRoleTokens,
26+
UsePolicyWithOpenRoleTokens,
27+
MintRolesTokens,
28+
TokenMetadataFile,
29+
TokenMetadata,
30+
Recipient,
31+
TokenQuantity,
32+
RoleTokenConfiguration,
33+
RolesConfiguration,
34+
} from "./rolesConfigurations.js";
1135
export {
1236
GetContractsResponse,
1337
GetContractsRequest,
1438
ContractsRange,
15-
CreateContractRequest,
16-
CreateContractResponse,
39+
ContractOrSourceId,
40+
BuildCreateContractTxRequest,
41+
BuildCreateContractTxRequestWithContract,
42+
BuildCreateContractTxRequestWithSourceId,
43+
BuildCreateContractTxRequestOptions,
44+
BuildCreateContractTxResponse,
1745
} from "./endpoints/collection.js";
1846
export { TxHeader } from "./transaction/header.js";
1947
export {
2048
TransactionsRange,
2149
GetTransactionsForContractResponse,
2250
} from "./transaction/endpoints/collection.js";
51+
2352
export { TransactionDetails } from "./transaction/details.js";
53+
54+
export { TransactionTextEnvelope } from "./transaction/endpoints/collection.js";

‎packages/runtime/client/rest/src/contract/role.ts

-44
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
import * as t from "io-ts/lib/index.js";
2+
3+
import { PolicyId, RoleName } from "@marlowe.io/language-core-v1";
4+
5+
import * as G from "@marlowe.io/language-core-v1/guards";
6+
7+
/**
8+
* @category Roles Configuration
9+
*/
10+
export interface AddressBech32Brand {
11+
readonly AddressBech32: unique symbol;
12+
}
13+
14+
export const AddressBech32Guard = t.brand(
15+
t.string,
16+
(s): s is t.Branded<string, AddressBech32Brand> => true,
17+
"AddressBech32"
18+
);
19+
20+
/**
21+
* Cardano Address in a Bech32 format
22+
* @category Roles Configuration
23+
*/
24+
export type AddressBech32 = t.TypeOf<typeof AddressBech32Guard>;
25+
26+
/**
27+
* Definition a of Closed Role Tlken
28+
* @remarks
29+
* - It is only defined by the Address where the token is distributed
30+
* @category Roles Configuration
31+
*/
32+
export type ClosedRole = AddressBech32;
33+
export const ClosedRoleGuard: t.Type<ClosedRole, string> = AddressBech32Guard;
34+
35+
/**
36+
* Definition of an Open Role Token
37+
* @category Roles Configuration
38+
*/
39+
export type OpenRole = "OpenRole";
40+
export const OpenRoleGuard = t.literal("OpenRole");
41+
42+
/**
43+
* Construction of an Open Role Token
44+
* @category Roles Configuration
45+
*/
46+
export const openRole = "OpenRole";
47+
48+
/**
49+
* Definition of the Openness of a Role Token
50+
* @category Roles Configuration
51+
*/
52+
export type Openness = ClosedRole | OpenRole;
53+
export const OpennessGuard: t.Type<Openness, string> = t.union([
54+
ClosedRoleGuard,
55+
OpenRoleGuard,
56+
]);
57+
58+
/**
59+
* @category Roles Configuration
60+
*/
61+
export type UsePolicyWithClosedRoleTokens = PolicyId;
62+
63+
export const UsePolicyWithClosedRoleTokensGuard: t.Type<UsePolicyWithClosedRoleTokens> =
64+
G.PolicyId;
65+
66+
/**
67+
* @category Roles Configuration
68+
*/
69+
export interface UsePolicyWithOpenRoleTokens {
70+
script: OpenRole;
71+
policyId: PolicyId;
72+
openRoleNames: RoleName[];
73+
}
74+
export const UsePolicyWithOpenRoleTokensGuard: t.Type<UsePolicyWithOpenRoleTokens> =
75+
t.type({
76+
script: OpenRoleGuard,
77+
policyId: G.PolicyId,
78+
openRoleNames: t.array(G.RoleName),
79+
});
80+
81+
/**
82+
* @category Roles Configuration
83+
*/
84+
export interface TokenMetadataFile {
85+
name: string;
86+
src: string;
87+
mediaType: string;
88+
}
89+
90+
export const TokenMetadataFileGuard: t.Type<TokenMetadataFile> = t.type({
91+
name: t.string,
92+
src: t.string,
93+
mediaType: t.string,
94+
});
95+
96+
/**
97+
* Token Metadata (CIP-25)
98+
* @category Roles Configuration
99+
* @see
100+
* - https://github.com/cardano-foundation/CIPs/blob/master/CIP-0025/README.md
101+
*/
102+
export interface TokenMetadata {
103+
name?: string;
104+
image?: string;
105+
mediaType: string;
106+
description: string;
107+
files: TokenMetadataFile[];
108+
}
109+
110+
export const TokenMetadataGuard: t.Type<TokenMetadata> = t.intersection([
111+
t.type({
112+
mediaType: t.string,
113+
description: t.string,
114+
files: t.array(TokenMetadataFileGuard),
115+
}),
116+
t.partial({ name: t.string }),
117+
t.partial({ image: t.string }),
118+
]);
119+
120+
/**
121+
* @category Roles Configuration
122+
*/
123+
export interface ClosedNFTWithMetadata {
124+
address: AddressBech32;
125+
metadata?: TokenMetadata;
126+
}
127+
128+
/**
129+
* @category Roles Configuration
130+
*/
131+
export type Recipient = Openness;
132+
133+
export const RecipientGuard: t.Type<Recipient, string> = t.union([
134+
OpenRoleGuard,
135+
ClosedRoleGuard,
136+
]);
137+
138+
/**
139+
* @category Roles Configuration
140+
*/
141+
export type TokenQuantity = bigint;
142+
143+
export const TokenQuantityGuard: t.Type<TokenQuantity> = t.bigint;
144+
145+
/**
146+
* @category Roles Configuration
147+
*/
148+
export interface RoleTokenConfiguration {
149+
recipients:
150+
| { [x: string & t.Brand<AddressBech32Brand>]: TokenQuantity }
151+
| { OpenRole: TokenQuantity };
152+
metadata?: TokenMetadata;
153+
}
154+
155+
export const RoleTokenConfigurationGuard: t.Type<RoleTokenConfiguration> =
156+
t.intersection([
157+
t.type({
158+
recipients: t.union([
159+
t.record(OpenRoleGuard, TokenQuantityGuard),
160+
t.record(ClosedRoleGuard, TokenQuantityGuard),
161+
]),
162+
}),
163+
t.partial({ metadata: TokenMetadataGuard }),
164+
]);
165+
166+
/**
167+
* @category Roles Configuration
168+
*/
169+
export type MintRolesTokens = { [x: RoleName]: RoleTokenConfiguration };
170+
171+
export const MintRolesTokensGuard: t.Type<MintRolesTokens> = t.record(
172+
G.RoleName,
173+
RoleTokenConfigurationGuard
174+
);
175+
176+
/**
177+
* Defines how to configure Roles over Cardano at the creation of a Marlowe Contract.
178+
* @see
179+
* Smart Constructors are available to ease the configuration:
180+
* - {@link @marlowe.io/runtime-rest-client!contract.useMintedRoles}
181+
* - {@link @marlowe.io/runtime-rest-client!contract.mintRole}
182+
* @category Endpoint : Build Create Contract Tx
183+
* @category Roles Configuration
184+
*/
185+
export type RolesConfiguration =
186+
| UsePolicyWithClosedRoleTokens
187+
| UsePolicyWithOpenRoleTokens
188+
| MintRolesTokens;
189+
190+
export const RolesConfigurationGuard = t.union([
191+
UsePolicyWithClosedRoleTokensGuard,
192+
UsePolicyWithOpenRoleTokensGuard,
193+
MintRolesTokensGuard,
194+
]);
195+
196+
/**
197+
* Configure Roles using tokens previously Minted. These Role Tokens are already defined (via an NFT platform, cardano-cli, another Marlowe Contract Created, etc.. )
198+
* @param policyId The policy Id of All the token roles defined in the Marlowe Contract DSL
199+
* @param openRoleNames defines all the Roles to be Open (Others will be Closed)
200+
* @remarks
201+
* It is under the user's responsability to create and distribute properly these role tokens
202+
* - Make sure all the Token Name are minted and match all the Role Names defined in the contract
203+
* - Depending on the Marlowe Contract logic, make sure the tokens are distributed to the right wallet
204+
* When using Open Role Tokens
205+
* - Thread Role Token needs to me minted when using Open Roles (by default threadRoleName = "")
206+
* - see {@link index.RestClient#buildCreateContractTx | Build Create Contract Tx }
207+
* @category Endpoint : Build Create Contract Tx
208+
* @category Roles Configuration
209+
*/
210+
export const useMintedRoles = (
211+
policyId: PolicyId,
212+
openRoleNames?: RoleName[]
213+
): RolesConfiguration =>
214+
openRoleNames
215+
? { script: openRole, policyId: policyId, openRoleNames: openRoleNames }
216+
: (policyId as UsePolicyWithClosedRoleTokens);
217+
218+
/**
219+
* Configure the minting of a Closed Role Token.
220+
* @param openness where to distribute the token (Either openly or closedly)
221+
* @param quantity Quantity of the Closed Role Token (by Default an NFT (==1))
222+
* @param metadata Token Metadata of the Token
223+
* @category Endpoint : Build Create Contract Tx
224+
* @category Roles Configuration
225+
*/
226+
export const mintRole = (
227+
openness: Openness,
228+
quantity?: TokenQuantity,
229+
metadata?: TokenMetadata
230+
): RoleTokenConfiguration =>
231+
OpenRoleGuard.is(openness)
232+
? {
233+
recipients: { [openRole]: quantity ? quantity : 1n },
234+
metadata: metadata,
235+
}
236+
: {
237+
recipients: { [openness]: quantity ? quantity : 1n },
238+
metadata: metadata,
239+
};

‎packages/runtime/client/rest/src/index.ts

+25-26
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,9 @@ import { submitContractViaAxios } from "./contract/endpoints/singleton.js";
4141
import { ContractDetails } from "./contract/details.js";
4242
import { TransactionDetails } from "./contract/transaction/details.js";
4343
import { CreateContractSourcesResponse } from "./contract/endpoints/sources.js";
44+
import { BuildCreateContractTxRequestWithContract } from "./contract/index.js";
4445
// import curlirize from 'axios-curlirize';
4546

46-
// TODO: DELETE
47-
// export * from "./contract/index.js";
48-
// export * from "./withdrawal/index.js";
49-
// export * from "./payout/index.js";
50-
// TODO: Revisit
51-
export { Assets, Tokens } from "./payout/index.js";
52-
export { RolesConfig } from "./contract/index.js";
53-
// Jamie Straw suggestion: 20 endpoints
54-
// Runtime Rest API docs: 18 endpoints (missing, getPayouts and getPayoutById, I assume version 0.0.5)
55-
// Current TS-SDK: 16 endpoints
56-
// https://docs.marlowe.iohk.io/api
57-
// openapi.json on main (RC 0.0.5): 20 endpoints
5847
/**
5948
* The RestClient offers a simple abstraction for the {@link https://docs.marlowe.iohk.io/api/ | Marlowe Runtime REST API} endpoints.
6049
* You can create an instance of the RestClient using the {@link mkRestClient} function.
@@ -69,7 +58,6 @@ export { RolesConfig } from "./contract/index.js";
6958
*
7059
* **WARNING**: Not all endpoints are implemented yet.
7160
*/
72-
// DISCUSSION: @N.H: Should we rename this to RestClient?
7361
export interface RestClient {
7462
/**
7563
* Gets a paginated list of contracts {@link contract.ContractHeader }
@@ -89,12 +77,9 @@ export interface RestClient {
8977
* @throws DecodingError - If the response from the server can't be decoded
9078
* @see {@link https://docs.marlowe.iohk.io/api/create-a-new-contract | The backend documentation}
9179
*/
92-
// TODO: Jamie, remove the `s from the end of the endpoint name in the docs site
93-
// DISCUSSION: @Jamie, @N.H: Should this be called `buildCreateContractTx` instead? As it is not creating the
94-
// contract, rather it is creating the transaction to be signed
95-
createContract(
96-
request: Contracts.CreateContractRequest
97-
): Promise<Contracts.CreateContractResponse>;
80+
buildCreateContractTx(
81+
request: Contracts.BuildCreateContractTxRequest
82+
): Promise<Contracts.BuildCreateContractTxResponse>;
9883

9984
/**
10085
* Uploads a marlowe-object bundle to the runtime, giving back the hash of the main contract and the hashes of the intermediate objects.
@@ -135,6 +120,9 @@ export interface RestClient {
135120
* Create an unsigned transaction which applies inputs to a contract.
136121
* @see {@link https://docs.marlowe.iohk.io/api/apply-inputs-to-contract | The backend documentation}
137122
*/
123+
// TODO: Jamie, remove the `s from the end of the endpoint name in the docs site
124+
// DISCUSSION: @Jamie, @N.H: Should this be called `buildApplyInputsToContractTx` instead? As it is not applying inputs to the
125+
// contract, rather it is creating the transaction to be signed
138126
applyInputsToContract(
139127
request: Transactions.ApplyInputsToContractRequest
140128
): Promise<Transactions.TransactionTextEnvelope>;
@@ -166,6 +154,9 @@ export interface RestClient {
166154
* Build an unsigned transaction (sign with the {@link @marlowe.io/wallet!api.WalletAPI#signTx} procedure) which withdraws available payouts from a contract (when applied with the {@link @marlowe.io/runtime-rest-client!index.RestClient#submitWithdrawal} procedure).
167155
* @see {@link https://docs.marlowe.iohk.io/api/withdraw-payouts | The backend documentation}
168156
*/
157+
// TODO: Jamie, remove the `s from the end of the endpoint name in the docs site
158+
// DISCUSSION: @Jamie, @N.H: Should this be called `buildWithdrawPayoutsTx` instead? As it is not withdrawing the
159+
// payout, rather it is creating the transaction to be signed
169160
withdrawPayouts(
170161
request: Withdrawals.WithdrawPayoutsRequest
171162
): Promise<Withdrawals.WithdrawPayoutsResponse>;
@@ -257,14 +248,21 @@ export function mkRestClient(baseURL: string): RestClient {
257248
getContractById(contractId) {
258249
return unsafeTaskEither(Contract.getViaAxios(axiosInstance)(contractId));
259250
},
260-
createContract(request) {
251+
buildCreateContractTx(request) {
261252
const postContractsRequest = {
262-
contract: request.contract,
253+
contract: "contract" in request ? request.contract : request.sourceId,
263254
version: request.version,
264255
metadata: request.metadata ?? {},
265256
tags: request.tags ?? {},
266-
minUTxODeposit: request.minUTxODeposit,
267-
roles: request.roles,
257+
...(request.minimumLovelaceUTxODeposit && {
258+
minUTxODeposit: request.minimumLovelaceUTxODeposit,
259+
}),
260+
...(request.roles && {
261+
roles: request.roles,
262+
}),
263+
...(request.threadRoleName && {
264+
threadTokenName: request.threadRoleName,
265+
}),
268266
};
269267
const addressesAndCollaterals = {
270268
changeAddress: request.changeAddress,
@@ -274,7 +272,8 @@ export function mkRestClient(baseURL: string): RestClient {
274272
return unsafeTaskEither(
275273
Contracts.postViaAxios(axiosInstance)(
276274
postContractsRequest,
277-
addressesAndCollaterals
275+
addressesAndCollaterals,
276+
request.stakeAddress
278277
)
279278
);
280279
},
@@ -457,7 +456,7 @@ export interface ContractsAPI {
457456
/**
458457
* @see {@link https://docs.marlowe.iohk.io/api/create-contracts}
459458
*/
460-
post: Contracts.POST;
459+
post: Contracts.BuildCreateContractTxEndpoint;
461460
contract: {
462461
/**
463462
* Get a single contract by id
@@ -500,7 +499,7 @@ export interface ContractsAPI {
500499
* @description Dependency Injection for the Rest Client API
501500
* @hidden
502501
*/
503-
export type RestDI = { rest: FPTSRestAPI };
502+
export type RestDI = { deprecatedRestAPI: FPTSRestAPI; restClient: RestClient };
504503

505504
/**
506505
* @hidden

‎packages/runtime/core/src/address.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as t from "io-ts/lib/index.js";
22
import { iso, Newtype } from "newtype-ts";
33
import { fromNewtype } from "io-ts-types";
4-
import { optionFromNullable } from "io-ts-types";
54
import { TxOutRef } from "./tx/outRef.js";
65

76
export type AddressBech32 = Newtype<
@@ -18,3 +17,11 @@ export const AddressesAndCollaterals = t.type({
1817
usedAddresses: t.array(AddressBech32),
1918
collateralUTxOs: t.array(TxOutRef),
2019
});
20+
21+
export type StakeAddressBech32 = Newtype<
22+
{ readonly StakeAddressBech32: unique symbol },
23+
string
24+
>;
25+
export const StakeAddressBech32 = fromNewtype<StakeAddressBech32>(t.string);
26+
export const unStakeAddressBech32 = iso<StakeAddressBech32>().unwrap;
27+
export const stakeAddressBech32 = iso<StakeAddressBech32>().wrap;

‎packages/runtime/core/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ export * from "./tx/index.js";
66
export * from "./metadata.js";
77
export * from "./tag.js";
88
export * from "./contract/id.js";
9+
export * from "./sourceId.js";
910
export * from "./asset/index.js";
1011
export * from "./payout/index.js";

‎packages/runtime/core/src/sourceId.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import * as t from "io-ts/lib/index.js";
2+
3+
export type SourceId = string;
4+
export const SourceIdGuard = t.string;

‎packages/runtime/lifecycle/src/api.ts

+178-6
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ import {
66
PayoutAvailable,
77
PayoutId,
88
PayoutWithdrawn,
9+
StakeAddressBech32,
910
Tags,
1011
TxId,
1112
} from "@marlowe.io/runtime-core";
12-
import { RestDI, RolesConfig } from "@marlowe.io/runtime-rest-client";
13+
import { RestDI } from "@marlowe.io/runtime-rest-client";
14+
import { RolesConfiguration } from "@marlowe.io/runtime-rest-client/contract";
1315
import { ISO8601 } from "@marlowe.io/adapter/time";
14-
import { Contract, Environment, Input } from "@marlowe.io/language-core-v1";
16+
import {
17+
Contract,
18+
Environment,
19+
Input,
20+
RoleName,
21+
} from "@marlowe.io/language-core-v1";
1522
import { Next } from "@marlowe.io/language-core-v1/next";
1623

1724
export type RuntimeLifecycle = {
@@ -28,14 +35,179 @@ export type RuntimeLifecycle = {
2835
export type ContractsDI = WalletDI & RestDI;
2936

3037
export type CreateContractRequest = {
38+
/**
39+
* A Marlowe Contract to create over Cardano
40+
*/
3141
contract: Contract;
32-
roles?: RolesConfig;
42+
43+
/**
44+
* Marlowe contracts can have staking rewards for the ADA locked in the contract.
45+
* Use this field to set the recipient address of those rewards
46+
*/
47+
stakeAddress?: StakeAddressBech32;
48+
/**
49+
* @experimental
50+
* The Thread Roles capability is an implementation details of the runtime.
51+
* It allows you to provide a custom name if the thread role name is conflicting with other role names used.
52+
* @default
53+
* - the Thread Role Name is "" by default.
54+
* @see
55+
* - https://github.com/input-output-hk/marlowe-cardano/blob/main/marlowe-runtime/doc/open-roles.md
56+
*/
57+
threadRoleName?: RoleName;
58+
59+
/**
60+
* Role Token Configuration for the new contract passed in the `contract` field.
61+
*
62+
* <h4>Participants</h4>
63+
* <p>
64+
* Participants ({@link @marlowe.io/language-core-v1!index.Party | Party}) in a Marlowe Contract can be expressed in 2 ways:
65+
*
66+
* 1. **By Adressses** : When an address is fixed in the contract we don't need to provide further configuration.
67+
* 2. **By Roles** : When the participation is done through a Role Token, we need to define if that token is minted as part of the contract creation transaction or if it was minted beforehand.
68+
*
69+
* </p>
70+
*
71+
* <h4>Configuration Options</h4>
72+
* <p>
73+
*
74+
* - **When to create (mint)**
75+
* - **Within the Runtime** : At the contrat creation, these defined Roles Tokens will be minted "on the fly" by the runtime.
76+
* - **Without the Runtime** : before the creation, these Role Tokens are already defined (via an NFT platform, `cardano-cli`, another Marlowe Contract Created, etc.. )
77+
* - **How to distribute**
78+
* - **Closedly** (Closed Roles) : At the creation of contract or before, the Role Tokens are released to the participants. All the participants are known at the creation and therefore we consider the participation as being closed.
79+
* - **Openly** (Open Roles) : Whoever applies an input (IDeposit or IChoice) on the contract `contract` first will be identified as a participant by receiving the Role Token in their wallet. In that case, participants are unknown at the creation and the participation is open to any meeting the criteria.
80+
* - **With or without Metadata**
81+
* - **Quantities to create(Mint)** : When asking to mint the tokens within the Runtime, quantities can defined as well.
82+
*
83+
* Smart Constructors are available to ease these configuration:
84+
* - {@link @marlowe.io/runtime-rest-client!contract.useMintedRoles}
85+
* - {@link @marlowe.io/runtime-rest-client!contract.mintRole}
86+
*
87+
* @remarks
88+
* - The Distribution can be a mix of Closed and Open Role Tokens configuration. See examples below.
89+
* </p>
90+
*
91+
* @example
92+
*
93+
* ```ts
94+
* //////////////
95+
* // #1 - Mint Role Tokens
96+
* //////////////
97+
* const anAddressBech32 = "addr_test1qqe342swyfn75mp2anj45f8ythjyxg6m7pu0pznptl6f2d84kwuzrh8c83gzhrq5zcw7ytmqc863z5rhhwst3w4x87eq0td9ja"
98+
* const aMintingConfiguration =
99+
* { "closed_Role_A_NFT" : mintRole(anAddressBech32)
100+
* , "closed_Role_B_FT" :
101+
* mintRole(
102+
* anAddressBech32,
103+
* 5, // Quantities
104+
* { "name": "closed_Role_B_FT Marlowe Role Token",
105+
"description": "These are metadata for closedRoleB",
106+
* image": "ipfs://QmaQMH7ybS9KmdYQpa4FMtAhwJH5cNaacpg4fTwhfPvcwj",
107+
* "mediaType": "image/png",
108+
* "files": [
109+
* {
110+
* "name": "icon-1000",
111+
* "mediaType": "image/webp",
112+
* "src": "ipfs://QmUbvavFxGSSEo3ipQf7rjrELDvXHDshWkHZSpV8CVdSE5"
113+
* }
114+
* ]
115+
* })
116+
* , "open_Role_C" : mkMintOpenRoleToken()
117+
* , "open_Role_D" : mkMintOpenRoleToken(
118+
* 2, // Quantities
119+
* { "name": "open_Role_D Marlowe Role Token",
120+
"description": "These are metadata for closedRoleB",
121+
* image": "ipfs://QmaQMH7ybS9KmdYQpa4FMtAhwJH5cNaacpg4fTwhfPvcwj",
122+
* "mediaType": "image/png",
123+
* "files": [
124+
* {
125+
* "name": "icon-1000",
126+
* "mediaType": "image/webp",
127+
* "src": "ipfs://QmUbvavFxGSSEo3ipQf7rjrELDvXHDshWkHZSpV8CVdSE5"
128+
* }
129+
* ]
130+
* })
131+
* }
132+
*
133+
* //////////////
134+
* // #2 Use Minted Roles Tokens
135+
* const aUseMintedRoleTokensConfiguration =
136+
* useMintedRoles(
137+
* "e68f1cea19752d1292b4be71b7f5d2b3219a15859c028f7454f66cdf",
138+
* ["role_A","role_C"]
139+
* )
140+
* ```
141+
*
142+
* @see
143+
* - {@link @marlowe.io/runtime-rest-client!contract.useMintedRoles}
144+
* - {@link @marlowe.io/runtime-rest-client!contract.mintRole}
145+
* - Open Roles Runtime Implementation : https://github.com/input-output-hk/marlowe-cardano/blob/main/marlowe-runtime/doc/open-roles.md
146+
*/
147+
roles?: RolesConfiguration;
148+
149+
/**
150+
* Marlowe Tags are stored as Metadata within the Transaction Metadata under the top-level Marlowe Reserved Key (`1564`).
151+
* Tags allows to Query created Marlowe Contracts via {@link @marlowe.io/runtime-rest-client!index.RestClient#getContracts | Get contracts }
152+
*
153+
* <h4>Properties</h4>
154+
*
155+
* 1. They aren't limited size-wise like regular metadata fields are over Cardano.
156+
* 2. Metadata can be associated under each tag
157+
*
158+
* @example
159+
* ```ts
160+
* const myTags : Tags = { "My Tag 1 That can be as long as I want": // Not limited to 64 bytes
161+
* { a: 0
162+
* , b : "Tag 1 content" // Limited to 64 bytes (Cardano Metadata constraint)
163+
* },
164+
* "MyTag2": { c: 0, d : "Tag 2 content"}};
165+
* ```
166+
*/
33167
tags?: Tags;
168+
/**
169+
* Cardano Metadata about the contract creation.
170+
* <h4>Properties</h4>
171+
* <p>
172+
* Metadata can be expressed as a JSON object with some restrictions:
173+
* - All top-level keys must be integers between 0 and 2^63 - 1.
174+
* - Each metadata value is tagged with its type.
175+
* - Strings must be at most 64 characters long (64 bytes) when UTF-8 is encoded.
176+
* - Bytestrings are hex-encoded, with a maximum length of 64 bytes.
177+
*
178+
* Metadata aren't stored as JSON on the Cardano blockchain but are instead stored using a compact binary encoding (CBOR).
179+
* The binary encoding of metadata values supports three simple types:
180+
* - Integers in the range `-(2^63 - 1)` to `2^63 - 1`
181+
* - Strings (UTF-8 encoded)
182+
* - Bytestrings
183+
* - And two compound types:
184+
* - Lists of metadata values
185+
* - Mappings from metadata values to metadata values
186+
* </p>
187+
* It is possible to transform any JSON object into this schema (See https://developers.cardano.org/docs/transaction-metadata )
188+
* @see
189+
* https://developers.cardano.org/docs/transaction-metadata
190+
*/
34191
metadata?: Metadata;
35-
minUTxODeposit?: number;
36-
};
37192

38-
export const minUTxODepositDefault: number = 3_000_000;
193+
/**
194+
* Minimum Lovelace value to add on the UTxO created (Representing the Marlowe Contract Created on the ledger).This value
195+
* is computed automatically within the Runtime, so this parameter is only necessary if you need some custom adjustment.
196+
*
197+
* <h4>Justification</h4>
198+
* <p>Creating a Marlowe contract over Cardano is about creating UTxO entries on the Ledger.
199+
*
200+
* To protect the ledger from growing beyond a certain size that will cost too much to maintain,
201+
* a constraint called "Minimum ada value requirement (minimumLovelaceUTxODeposit)" that adjust
202+
* the value (in ADA) of each UTxO has been added.
203+
*
204+
* The bigger the UTxOs entries are in terms of bytesize, the higher the value if minimum ADA required.</p>
205+
*
206+
* @see
207+
* https://docs.cardano.org/native-tokens/minimum-ada-value-requirement
208+
*/
209+
minimumLovelaceUTxODeposit?: number;
210+
};
39211

40212
export type ApplyInputsRequest = {
41213
inputs: Input[];

‎packages/runtime/lifecycle/src/browser/index.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
} from "@marlowe.io/wallet/browser";
55
import * as Generic from "../generic/runtime.js";
66

7-
import { mkFPTSRestClient } from "@marlowe.io/runtime-rest-client";
7+
import {
8+
mkFPTSRestClient,
9+
mkRestClient,
10+
} from "@marlowe.io/runtime-rest-client";
811

912
/**
1013
* Options for creating a RuntimeLifecycle instance using the browser wallet.
@@ -31,6 +34,7 @@ export async function mkRuntimeLifecycle({
3134
walletName,
3235
}: BrowserRuntimeLifecycleOptions) {
3336
const wallet = await mkBrowserWallet(walletName);
34-
const restClient = mkFPTSRestClient(runtimeURL);
35-
return Generic.mkRuntimeLifecycle(restClient, wallet);
37+
const deprecatedRestAPI = mkFPTSRestClient(runtimeURL);
38+
const restClient = mkRestClient(runtimeURL);
39+
return Generic.mkRuntimeLifecycle(deprecatedRestAPI, restClient, wallet);
3640
}

‎packages/runtime/lifecycle/src/generic/contracts.ts

+60-40
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
ContractsAPI,
88
ContractsDI,
99
CreateContractRequest,
10-
minUTxODepositDefault,
1110
} from "../api.js";
1211

1312
import { getAddressesAndCollaterals, WalletAPI } from "@marlowe.io/wallet/api";
@@ -20,20 +19,26 @@ import {
2019
HexTransactionWitnessSet,
2120
unAddressBech32,
2221
unPolicyId,
22+
transactionWitnessSetTextEnvelope,
2323
} from "@marlowe.io/runtime-core";
2424

25-
import { FPTSRestAPI } from "@marlowe.io/runtime-rest-client";
25+
import { FPTSRestAPI, RestClient } from "@marlowe.io/runtime-rest-client";
2626
import { DecodingError } from "@marlowe.io/adapter/codec";
27-
import { TransactionTextEnvelope } from "@marlowe.io/runtime-rest-client/contract/transaction/endpoints/collection";
27+
2828
import { Next, noNext } from "@marlowe.io/language-core-v1/next";
2929
import { isNone, none, Option } from "fp-ts/lib/Option.js";
30-
import { ContractsRange } from "@marlowe.io/runtime-rest-client/contract/index";
30+
import {
31+
BuildCreateContractTxResponse,
32+
ContractsRange,
33+
TransactionTextEnvelope,
34+
} from "@marlowe.io/runtime-rest-client/contract";
3135

3236
export function mkContractLifecycle(
3337
wallet: WalletAPI,
34-
rest: FPTSRestAPI
38+
deprecatedRestAPI: FPTSRestAPI,
39+
restClient: RestClient
3540
): ContractsAPI {
36-
const di = { wallet, rest };
41+
const di = { wallet, deprecatedRestAPI, restClient };
3742
return {
3843
createContract: submitCreateTx(di),
3944
applyInputs: submitApplyInputsTx(di),
@@ -43,31 +48,33 @@ export function mkContractLifecycle(
4348
}
4449

4550
const submitCreateTx =
46-
({ wallet, rest }: ContractsDI) =>
51+
({ wallet, restClient }: ContractsDI) =>
4752
(
4853
createContractRequest: CreateContractRequest
4954
): Promise<[ContractId, TxId]> => {
5055
return unsafeTaskEither(
51-
submitCreateTxFpTs(rest)(wallet)(createContractRequest)
56+
submitCreateTxFpTs(restClient)(wallet)(createContractRequest)
5257
);
5358
};
5459

5560
const submitApplyInputsTx =
56-
({ wallet, rest }: ContractsDI) =>
61+
({ wallet, deprecatedRestAPI }: ContractsDI) =>
5762
async (
5863
contractId: ContractId,
5964
applyInputsRequest: ApplyInputsRequest
6065
): Promise<TxId> => {
6166
return unsafeTaskEither(
62-
submitApplyInputsTxFpTs(rest)(wallet)(contractId)(applyInputsRequest)
67+
submitApplyInputsTxFpTs(deprecatedRestAPI)(wallet)(contractId)(
68+
applyInputsRequest
69+
)
6370
);
6471
};
6572

6673
const getApplicableInputs =
67-
({ wallet, rest }: ContractsDI) =>
74+
({ wallet, deprecatedRestAPI }: ContractsDI) =>
6875
async (contractId: ContractId, environement: Environment): Promise<Next> => {
6976
const contractDetails = await unsafeTaskEither(
70-
rest.contracts.contract.get(contractId)
77+
deprecatedRestAPI.contracts.contract.get(contractId)
7178
);
7279
if (isNone(contractDetails.currentContract)) {
7380
return noNext;
@@ -76,13 +83,15 @@ const getApplicableInputs =
7683
contractDetails.roleTokenMintingPolicyId
7784
);
7885
return await unsafeTaskEither(
79-
rest.contracts.contract.next(contractId)(environement)(parties)
86+
deprecatedRestAPI.contracts.contract.next(contractId)(environement)(
87+
parties
88+
)
8089
);
8190
}
8291
};
8392

8493
const getContractIds =
85-
({ rest, wallet }: ContractsDI) =>
94+
({ deprecatedRestAPI, wallet }: ContractsDI) =>
8695
async (): Promise<ContractId[]> => {
8796
const partyAddresses = [
8897
await wallet.getChangeAddress(),
@@ -93,7 +102,9 @@ const getContractIds =
93102
range: Option<ContractsRange>,
94103
acc: ContractId[]
95104
): Promise<ContractId[]> => {
96-
const result = await rest.contracts.getHeadersByRange(range)(kwargs)();
105+
const result = await deprecatedRestAPI.contracts.getHeadersByRange(range)(
106+
kwargs
107+
)();
97108
if (result._tag === "Left") throw result.left;
98109
const response = result.right;
99110
const contractIds = [
@@ -128,7 +139,7 @@ const getParties: (
128139
};
129140

130141
export const submitCreateTxFpTs: (
131-
client: FPTSRestAPI
142+
client: RestClient
132143
) => (
133144
wallet: WalletAPI
134145
) => (
@@ -138,39 +149,48 @@ export const submitCreateTxFpTs: (
138149
pipe(
139150
tryCatchDefault(() => getAddressesAndCollaterals(wallet)),
140151
TE.chain((addressesAndCollaterals) =>
141-
client.contracts.post(
142-
{
143-
contract: createContractRequest.contract,
152+
tryCatchDefault(() =>
153+
client.buildCreateContractTx({
144154
version: "v1",
155+
156+
changeAddress: addressesAndCollaterals.changeAddress,
157+
usedAddresses: addressesAndCollaterals.usedAddresses,
158+
collateralUTxOs: addressesAndCollaterals.collateralUTxOs,
159+
stakeAddress: createContractRequest.stakeAddress,
160+
161+
contract: createContractRequest.contract,
162+
threadRoleName: createContractRequest.threadRoleName,
145163
roles: createContractRequest.roles,
146-
tags: createContractRequest.tags ? createContractRequest.tags : {},
147-
metadata: createContractRequest.metadata
148-
? createContractRequest.metadata
149-
: {},
150-
minUTxODeposit: createContractRequest.minUTxODeposit
151-
? createContractRequest.minUTxODeposit
152-
: minUTxODepositDefault,
153-
},
154-
addressesAndCollaterals
164+
165+
tags: createContractRequest.tags,
166+
metadata: createContractRequest.metadata,
167+
minimumLovelaceUTxODeposit:
168+
createContractRequest.minimumLovelaceUTxODeposit,
169+
})
155170
)
156171
),
157-
TE.chainW((contractTextEnvelope) =>
158-
pipe(
159-
tryCatchDefault(() => wallet.signTx(contractTextEnvelope.tx.cborHex)),
160-
TE.chain((hexTransactionWitnessSet) =>
161-
client.contracts.contract.put(
162-
contractTextEnvelope.contractId,
163-
hexTransactionWitnessSet
164-
)
165-
),
166-
TE.map(() => contractTextEnvelope.contractId)
167-
)
172+
TE.chainW(
173+
(buildCreateContractTxResponse: BuildCreateContractTxResponse) =>
174+
pipe(
175+
tryCatchDefault(() =>
176+
wallet.signTx(buildCreateContractTxResponse.tx.cborHex)
177+
),
178+
TE.chain((hexTransactionWitnessSet) =>
179+
tryCatchDefault(() =>
180+
client.submitContract(
181+
buildCreateContractTxResponse.contractId,
182+
transactionWitnessSetTextEnvelope(hexTransactionWitnessSet)
183+
)
184+
)
185+
),
186+
TE.map(() => buildCreateContractTxResponse.contractId)
187+
)
168188
),
169189
TE.map((contractId) => [contractId, contractIdToTxId(contractId)])
170190
);
171191

172192
export const createContractFpTs: (
173-
client: FPTSRestAPI
193+
client: RestClient
174194
) => (
175195
wallet: WalletAPI
176196
) => (

‎packages/runtime/lifecycle/src/generic/payouts.ts

+19-12
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ import {
1717
withdrawalIdToTxId,
1818
} from "@marlowe.io/runtime-core";
1919

20-
import { FPTSRestAPI } from "@marlowe.io/runtime-rest-client";
20+
import { FPTSRestAPI, RestClient } from "@marlowe.io/runtime-rest-client";
2121

22-
import * as Rest from "@marlowe.io/runtime-rest-client";
22+
import * as RestPayout from "@marlowe.io/runtime-rest-client/payout";
2323

2424
import { DecodingError } from "@marlowe.io/adapter/codec";
2525
import { stringify } from "json-bigint";
2626

2727
export function mkPayoutLifecycle(
2828
wallet: WalletAPI,
29-
rest: FPTSRestAPI
29+
deprecatedRestAPI: FPTSRestAPI,
30+
restClient: RestClient
3031
): PayoutsAPI {
31-
const di = { wallet, rest };
32+
const di = { wallet, deprecatedRestAPI, restClient };
3233
return {
3334
available: fetchAvailablePayouts(di),
3435
withdraw: withdrawPayouts(di),
@@ -37,22 +38,28 @@ export function mkPayoutLifecycle(
3738
}
3839

3940
const fetchAvailablePayouts =
40-
({ wallet, rest }: PayoutsDI) =>
41+
({ wallet, deprecatedRestAPI }: PayoutsDI) =>
4142
(filters?: Filters): Promise<PayoutAvailable[]> => {
4243
return unsafeTaskEither(
43-
fetchAvailablePayoutsFpTs(rest)(wallet)(O.fromNullable(filters))
44+
fetchAvailablePayoutsFpTs(deprecatedRestAPI)(wallet)(
45+
O.fromNullable(filters)
46+
)
4447
);
4548
};
4649
const withdrawPayouts =
47-
({ wallet, rest }: PayoutsDI) =>
50+
({ wallet, deprecatedRestAPI }: PayoutsDI) =>
4851
(payoutIds: PayoutId[]): Promise<void> => {
49-
return unsafeTaskEither(withdrawPayoutsFpTs(rest)(wallet)(payoutIds));
52+
return unsafeTaskEither(
53+
withdrawPayoutsFpTs(deprecatedRestAPI)(wallet)(payoutIds)
54+
);
5055
};
5156
const fetchWithdrawnPayouts =
52-
({ wallet, rest }: PayoutsDI) =>
57+
({ wallet, deprecatedRestAPI }: PayoutsDI) =>
5358
(filters?: Filters): Promise<PayoutWithdrawn[]> => {
5459
return unsafeTaskEither(
55-
fetchWithdrawnPayoutsFpTs(rest)(wallet)(O.fromNullable(filters))
60+
fetchWithdrawnPayoutsFpTs(deprecatedRestAPI)(wallet)(
61+
O.fromNullable(filters)
62+
)
5663
);
5764
};
5865

@@ -163,12 +170,12 @@ const fetchWithdrawnPayoutsFpTs: (
163170
)
164171
);
165172

166-
const convertAsset: (assets: Rest.Assets) => Assets = (restAssets) => ({
173+
const convertAsset: (assets: RestPayout.Assets) => Assets = (restAssets) => ({
167174
lovelaces: restAssets.lovelace,
168175
tokens: convertTokens(restAssets.tokens),
169176
});
170177

171-
const convertTokens: (tokens: Rest.Tokens) => Tokens = (restTokens) =>
178+
const convertTokens: (tokens: RestPayout.Tokens) => Tokens = (restTokens) =>
172179
Object.entries(restTokens)
173180
.map(([policyId, x]) =>
174181
Object.entries(x).map(([assetName, quantity]) =>
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { RuntimeLifecycle } from "../api.js";
22
import { WalletAPI } from "@marlowe.io/wallet/api";
33

4-
import { FPTSRestAPI } from "@marlowe.io/runtime-rest-client";
4+
import { FPTSRestAPI, RestClient } from "@marlowe.io/runtime-rest-client";
55

66
import { mkPayoutLifecycle } from "./payouts.js";
77
import { mkContractLifecycle } from "./contracts.js";
88

99
export function mkRuntimeLifecycle(
10-
restAPI: FPTSRestAPI,
10+
deprecatedRestAPI: FPTSRestAPI,
11+
restClient: RestClient,
1112
wallet: WalletAPI
1213
): RuntimeLifecycle {
1314
return {
1415
wallet: wallet,
15-
contracts: mkContractLifecycle(wallet, restAPI),
16-
payouts: mkPayoutLifecycle(wallet, restAPI),
16+
contracts: mkContractLifecycle(wallet, deprecatedRestAPI, restClient),
17+
payouts: mkPayoutLifecycle(wallet, deprecatedRestAPI, restClient),
1718
};
1819
}

‎packages/runtime/lifecycle/src/index.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { WalletAPI } from "@marlowe.io/wallet";
1919
import * as Generic from "./generic/runtime.js";
20-
import { mkFPTSRestClient } from "@marlowe.io/runtime-rest-client";
20+
import { mkFPTSRestClient, mkRestClient } from "@marlowe.io/runtime-rest-client";
2121

2222
export * as Browser from "./browser/index.js";
2323

@@ -42,6 +42,7 @@ export function mkRuntimeLifecycle({
4242
runtimeURL,
4343
wallet,
4444
}: RuntimeLifecycleOptions) {
45-
const restClient = mkFPTSRestClient(runtimeURL);
46-
return Generic.mkRuntimeLifecycle(restClient, wallet);
45+
const deprecatedRestAPI = mkFPTSRestClient(runtimeURL);
46+
const restClient = mkRestClient(runtimeURL);
47+
return Generic.mkRuntimeLifecycle(deprecatedRestAPI,restClient, wallet);
4748
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
mkFPTSRestClient,
3+
mkRestClient,
4+
} from "@marlowe.io/runtime-rest-client";
5+
import * as S from "@marlowe.io/wallet/nodejs";
6+
import * as Generic from "../generic/runtime.js";
7+
8+
export async function mkRuntimeLifecycle({
9+
runtimeURL,
10+
context,
11+
privateKeyBech32,
12+
}: {
13+
runtimeURL: string;
14+
context: S.Context;
15+
privateKeyBech32: string;
16+
}) {
17+
const wallet = await S.SingleAddressWallet.Initialise(
18+
context,
19+
privateKeyBech32
20+
);
21+
22+
const deprecatedRestAPI = mkFPTSRestClient(runtimeURL);
23+
const restClient = mkRestClient(runtimeURL);
24+
return Generic.mkRuntimeLifecycle(deprecatedRestAPI, restClient, wallet);
25+
}

‎packages/runtime/lifecycle/test/examples/swap.ada.token.e2e.spec.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,17 @@ import {
1313
} from "../context.js";
1414
import { provisionAnAdaAndTokenProvider } from "../provisionning.js";
1515
import console from "console";
16-
import { runtimeTokenToMarloweTokenValue } from "@marlowe.io/runtime-core";
16+
import {
17+
runtimeTokenToMarloweTokenValue,
18+
unAddressBech32,
19+
} from "@marlowe.io/runtime-core";
1720
import { onlyByContractIds } from "@marlowe.io/runtime-lifecycle/api";
1821
import { MINUTES } from "@marlowe.io/adapter/time";
22+
import { mintRole, openRole } from "@marlowe.io/runtime-rest-client/contract";
23+
import {
24+
AddressBech32,
25+
AddressBech32Guard,
26+
} from "@marlowe.io/runtime-rest-client/contract/rolesConfigurations.js";
1927

2028
global.console = console;
2129

@@ -59,8 +67,12 @@ describe("swap", () => {
5967
).contracts.createContract({
6068
contract: swapContract,
6169
roles: {
62-
[swapRequest.provider.roleName]: adaProvider.address,
63-
[swapRequest.swapper.roleName]: tokenProvider.address,
70+
[swapRequest.provider.roleName]: mintRole(
71+
adaProvider.address as unknown as AddressBech32
72+
),
73+
[swapRequest.swapper.roleName]: mintRole(
74+
tokenProvider.address as unknown as AddressBech32
75+
),
6476
},
6577
});
6678
await runtime(adaProvider).wallet.waitConfirmation(txIdContractCreated);

‎packages/runtime/lifecycle/test/generic/payouts.e2e.spec.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import console from "console";
1616
import { runtimeTokenToMarloweTokenValue } from "@marlowe.io/runtime-core";
1717
import { onlyByContractIds } from "@marlowe.io/runtime-lifecycle/api";
1818
import { MINUTES } from "@marlowe.io/adapter/time";
19+
import { mintRole } from "@marlowe.io/runtime-rest-client/contract";
20+
import { AddressBech32 } from "@marlowe.io/runtime-rest-client/contract/rolesConfigurations.js";
1921

2022
global.console = console;
2123

@@ -52,8 +54,12 @@ describe("Payouts", () => {
5254
).contracts.createContract({
5355
contract: swapContract,
5456
roles: {
55-
[swapRequest.provider.roleName]: adaProvider.address,
56-
[swapRequest.swapper.roleName]: tokenProvider.address,
57+
[swapRequest.provider.roleName]: mintRole(
58+
adaProvider.address as unknown as AddressBech32
59+
),
60+
[swapRequest.swapper.roleName]: mintRole(
61+
tokenProvider.address as unknown as AddressBech32
62+
),
5763
},
5864
});
5965
await runtime(adaProvider).wallet.waitConfirmation(txCreatedContract);

‎packages/wallet/src/browser/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ export async function mkBrowserWallet(
7878
): Promise<WalletAPI> {
7979
if (
8080
getInstalledWalletExtensions()
81-
.map((extension) => extension.name)
82-
.includes(walletName)
81+
.map((extension) => extension.name.toLowerCase())
82+
.includes(walletName.toLowerCase())
8383
) {
8484
const extension = await window.cardano[walletName.toLowerCase()].enable();
8585
const di = { extension };

0 commit comments

Comments
 (0)
Please sign in to comment.