Skip to content

Commit

Permalink
start of the implementation of the new contract api
Browse files Browse the repository at this point in the history
  • Loading branch information
hrajchert authored and nhenin committed Apr 18, 2024
1 parent 6bc63f2 commit 256a957
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 117 deletions.
4 changes: 3 additions & 1 deletion packages/runtime/client/rest/src/index.ts
Expand Up @@ -732,7 +732,9 @@ export interface ContractsAPI {
* @description Dependency Injection for the Rest Client API
* @hidden
*/
export type RestDI = { deprecatedRestAPI: FPTSRestAPI; restClient: RestClient };
export type RestDI = { restClient: RestClient };

export type DeprecatedRestDI = { deprecatedRestAPI: FPTSRestAPI };

/**
* @hidden
Expand Down
14 changes: 11 additions & 3 deletions packages/runtime/lifecycle/src/api.ts
Expand Up @@ -6,7 +6,11 @@ import {
PayoutId,
PayoutWithdrawn,
} from "@marlowe.io/runtime-core";
import { RestClient, RestDI } from "@marlowe.io/runtime-rest-client";
import {
DeprecatedRestDI,
RestClient,
RestDI,
} from "@marlowe.io/runtime-rest-client";

import {
ApplicableActionsAPI,
Expand All @@ -20,10 +24,12 @@ import {
CanDeposit,
CanNotify,
GetApplicableActionsResponse,
} from "./generic/applicable-actions.js";
import {
ActiveContract,
ClosedContract,
ContractDetails,
} from "./generic/applicable-actions.js";
} from "./generic/new-contract-api.js";
import {
ContractsAPI,
CreateContractRequestBase,
Expand All @@ -45,6 +51,7 @@ export {
ContractDetails,
CreateContractRequestBase,
};
import * as NewContract from "./generic/new-contract-api.js";

/**
* This is the main entry point of the @marlowe.io/runtime-lifecycle package. It provides a set of APIs to
Expand All @@ -63,6 +70,7 @@ export interface RuntimeLifecycle {
* Access to the low-level REST API as defined in the {@link @marlowe.io/runtime-rest-client! } package. It is re-exported here for convenience.
*/
restClient: RestClient;
newContractAPI: NewContract.ContractsAPI;
/**
* The contracts API is a high level API that lets you create and interact with Marlowe contracts.
*/
Expand All @@ -74,7 +82,7 @@ export interface RuntimeLifecycle {
/**
* @hidden
*/
export type PayoutsDI = WalletDI & RestDI;
export type PayoutsDI = WalletDI & RestDI & DeprecatedRestDI;

/**
* @category PayoutsAPI
Expand Down
39 changes: 5 additions & 34 deletions packages/runtime/lifecycle/src/generic/applicable-actions.ts
Expand Up @@ -45,6 +45,11 @@ import { WalletAPI } from "@marlowe.io/wallet";
import * as Big from "@marlowe.io/adapter/bigint";
import { ContractSourceId } from "@marlowe.io/marlowe-object";
import { posixTimeToIso8601 } from "@marlowe.io/adapter/time";
import {
ActiveContract,
ContractDetails,
GetContractDetailsDI,
} from "./new-contract-api.js";

/**
* @experimental
Expand Down Expand Up @@ -834,37 +839,3 @@ function getApplicableActionFromCase(
});
}
}

// #region High level Contract Details
/**
* @category New ContractsAPI
*/
export type ClosedContract = {
type: "closed";
};

/**
* @category New ContractsAPI
*/
export type ActiveContract = {
type: "active";
contractId: ContractId;
currentState: MarloweState;
currentContract: Contract;
roleTokenMintingPolicyId: PolicyId;
};

/**
* This is the start of a high level API to get the contract details.
* The current restAPI is not clear wether the details that you get are
* from a closed or active contract. This API is just the start to get
* getApplicableInputs ready in production, but as part of a ContractsAPI
* refactoring, the whole contract details should be modeled.
* @category New ContractsAPI
*/
export type ContractDetails = ClosedContract | ActiveContract;

type GetContractDetailsDI = {
getContractDetails: (contractId: ContractId) => Promise<ContractDetails>;
};
// #endregion
112 changes: 33 additions & 79 deletions packages/runtime/lifecycle/src/generic/deprecated-contracts.ts
Expand Up @@ -34,6 +34,7 @@ import {
RestClient,
RestDI,
ItemRange,
DeprecatedRestDI,
} from "@marlowe.io/runtime-rest-client";
import { DecodingError } from "@marlowe.io/adapter/codec";

Expand Down Expand Up @@ -328,13 +329,13 @@ export function mkContractLifecycle(
const di = { wallet, deprecatedRestAPI, restClient };
return {
createContract: createContract(di),
applyInputs: applyInputsTx(di),
applyInputs: applyInputs(di),
getApplicableInputs: getApplicableInputs(di),
getContractIds: getContractIds(di),
getInputHistory: getInputHistory(di),
};
}
const getInputHistory =
export const getInputHistory =
({ restClient }: ContractsDI) =>
async (contractId: ContractId): Promise<SingleInputTx[]> => {
const transactionHeaders = await restClient.getTransactionsForContract({
Expand Down Expand Up @@ -390,7 +391,7 @@ const getInputHistory =
.flat();
};

const createContract =
export const createContract =
({ wallet, restClient }: ContractsDI) =>
async (
createContractRequest: CreateContractRequest
Expand Down Expand Up @@ -445,21 +446,8 @@ const createContract =
return [contractId, contractIdToTxId(contractId)];
};

const applyInputsTx =
({ wallet, deprecatedRestAPI }: ContractsDI) =>
async (
contractId: ContractId,
applyInputsRequest: ApplyInputsRequest
): Promise<TxId> => {
return unsafeTaskEither(
applyInputsTxFpTs(deprecatedRestAPI)(wallet)(contractId)(
applyInputsRequest
)
);
};

const getApplicableInputs =
({ wallet, deprecatedRestAPI }: ContractsDI) =>
({ wallet, deprecatedRestAPI }: ContractsDI & DeprecatedRestDI) =>
async (contractId: ContractId, environement: Environment): Promise<Next> => {
const contractDetails = await unsafeTaskEither(
deprecatedRestAPI.contracts.contract.get(contractId)
Expand All @@ -479,7 +467,7 @@ const getApplicableInputs =
};

const getContractIds =
({ deprecatedRestAPI, wallet }: ContractsDI) =>
({ deprecatedRestAPI, wallet }: ContractsDI & DeprecatedRestDI) =>
async (): Promise<ContractId[]> => {
const partyAddresses = [
await wallet.getChangeAddress(),
Expand Down Expand Up @@ -525,64 +513,30 @@ const getParties: (
return roles.concat([changeAddress]).concat(usedAddresses);
};

export const applyInputsTxFpTs: (
client: FPTSRestAPI
) => (
wallet: WalletAPI
) => (
contractId: ContractId
) => (
applyInputsRequest: ApplyInputsRequest
) => TE.TaskEither<Error | DecodingError, TxId> =
(client) => (wallet) => (contractId) => (applyInputsRequest) =>
pipe(
tryCatchDefault(() => getAddressesAndCollaterals(wallet)),
TE.chain((addressesAndCollaterals: AddressesAndCollaterals) =>
client.contracts.contract.transactions.post(
contractId,
{
inputs: applyInputsRequest.inputs,
version: "v1",
tags: applyInputsRequest.tags ? applyInputsRequest.tags : {},
metadata: applyInputsRequest.metadata
? applyInputsRequest.metadata
: {},
invalidBefore: applyInputsRequest.invalidBefore,
invalidHereafter: applyInputsRequest.invalidHereafter,
},
addressesAndCollaterals
)
),
TE.chainW((transactionTextEnvelope: TransactionTextEnvelope) =>
pipe(
tryCatchDefault(() =>
wallet.signTx(transactionTextEnvelope.tx.cborHex)
),
TE.chain((hexTransactionWitnessSet: HexTransactionWitnessSet) =>
client.contracts.contract.transactions.transaction.put(
contractId,
transactionTextEnvelope.transactionId,
hexTransactionWitnessSet
)
),
TE.map(() => transactionTextEnvelope.transactionId)
)
)
);

export const applyInputsFpTs: (
client: FPTSRestAPI
) => (
wallet: WalletAPI
) => (
contractId: ContractId
) => (
applyInputsRequest: ApplyInputsRequest
) => TE.TaskEither<Error | DecodingError, TxId> =
(client) => (wallet) => (contractId) => (applyInputsRequest) =>
pipe(
applyInputsTxFpTs(client)(wallet)(contractId)(applyInputsRequest),
TE.chainW((txId) =>
tryCatchDefault(() => wallet.waitConfirmation(txId).then((_) => txId))
)
);
export const applyInputs =
({ wallet, restClient }: ContractsDI) =>
async (
contractId: ContractId,
applyInputsRequest: ApplyInputsRequest
): Promise<TxId> => {
const addressesAndCollaterals = await getAddressesAndCollaterals(wallet);
const envelope = await restClient.applyInputsToContract({
contractId,
changeAddress: addressesAndCollaterals.changeAddress,
usedAddresses: addressesAndCollaterals.usedAddresses,
collateralUTxOs: addressesAndCollaterals.collateralUTxOs,
inputs: applyInputsRequest.inputs,
invalidBefore: applyInputsRequest.invalidBefore,
invalidHereafter: applyInputsRequest.invalidHereafter,
version: "v1",
metadata: applyInputsRequest.metadata,
tags: applyInputsRequest.tags,
});
const signed = await wallet.signTx(envelope.tx.cborHex);
await restClient.submitContractTransaction({
contractId,
transactionId: envelope.transactionId,
hexTransactionWitnessSet: signed,
});
return envelope.transactionId;
};

0 comments on commit 256a957

Please sign in to comment.