cardano-pab-client
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -7,3 +7,3 @@ /** | ||
import type * as S from "@emurgo/cardano-serialization-lib-browser"; | ||
import { ExecutionUnits, ExportTx, ExportTxInput, Redeemer, WalletInfo } from "../common"; | ||
import { ExecutionUnits, ExportTx, ExportTxInput, Redeemer, Result, WalletInfo } from "../common"; | ||
import TxInputsInfo from "./TxInputsInfo"; | ||
@@ -65,2 +65,5 @@ /** | ||
}; | ||
interface ExecutionUnitsEvaluator { | ||
evaluate: (balancedTx: string, inputsInfo: ExportTxInput[]) => Promise<Result<Array<[Redeemer, ExecutionUnits]>>>; | ||
} | ||
export default class Balancer { | ||
@@ -91,8 +94,8 @@ protocolParameters: ProtocolParameters; | ||
* rebalanceTx methods within the same object. | ||
* @param calculateExUnits Function that exposes the balanced transaction and the complete | ||
* information of the inputs to allow the calculation of the execution units of each redeemer | ||
* (this calculation could be done using the tx budget service, or with any other method). | ||
* @returns The fully-balanced transaction ready to be signed by a wallet. | ||
* @param exUnitsEvaluator An object that can evaluate the execution units of the redeemers of the | ||
* transaction. An instance of the `TxBudgetApi` can be used here. | ||
* @returns The fully-balanced transaction ready to be signed by a wallet, or an error if | ||
* something happened. | ||
*/ | ||
fullBalanceTx({ transaction, inputs }: ExportTx | Omit<ExportTx, "redeemers">, { utxos, collateral, changeAddress }: WalletInfo, { feeUpperBound, mergeSignerOutputs, changeOutputIndex }: BalanceTxConfig & RebalanceTxConfig, calculateExUnits: (balancedTx: string, inputsInfo: ExportTxInput[]) => Promise<Array<[Redeemer, ExecutionUnits]>>): Promise<string>; | ||
fullBalanceTx({ transaction, inputs }: ExportTx | Omit<ExportTx, "redeemers">, { utxos, collateral, changeAddress }: WalletInfo, { feeUpperBound, mergeSignerOutputs, changeOutputIndex }: BalanceTxConfig & RebalanceTxConfig, exUnitsEvaluator: ExecutionUnitsEvaluator): Promise<Result<string>>; | ||
/** | ||
@@ -99,0 +102,0 @@ * Balances the given transaction. |
@@ -46,3 +46,3 @@ "use strict"; | ||
const CoinSelection_1 = __importStar(require("./CoinSelection")); | ||
const serLibPrinter_1 = require("./serLibPrinter"); | ||
const common_1 = require("../common"); | ||
const TxInputsInfo_1 = __importDefault(require("./TxInputsInfo")); | ||
@@ -80,15 +80,24 @@ class Balancer { | ||
* rebalanceTx methods within the same object. | ||
* @param calculateExUnits Function that exposes the balanced transaction and the complete | ||
* information of the inputs to allow the calculation of the execution units of each redeemer | ||
* (this calculation could be done using the tx budget service, or with any other method). | ||
* @returns The fully-balanced transaction ready to be signed by a wallet. | ||
* @param exUnitsEvaluator An object that can evaluate the execution units of the redeemers of the | ||
* transaction. An instance of the `TxBudgetApi` can be used here. | ||
* @returns The fully-balanced transaction ready to be signed by a wallet, or an error if | ||
* something happened. | ||
*/ | ||
fullBalanceTx({ transaction, inputs }, { utxos, collateral, changeAddress }, { feeUpperBound, mergeSignerOutputs, changeOutputIndex }, calculateExUnits) { | ||
fullBalanceTx({ transaction, inputs }, { utxos, collateral, changeAddress }, { feeUpperBound, mergeSignerOutputs, changeOutputIndex }, exUnitsEvaluator) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const txInputsInfo = yield TxInputsInfo_1.default.init(transaction, inputs, utxos); | ||
const balancedTx = yield this.balanceTx(transaction, txInputsInfo, { utxos, collateral, changeAddress }, { feeUpperBound, mergeSignerOutputs }); | ||
const executionUnits = yield calculateExUnits(balancedTx, txInputsInfo.toExportTxInputs()); | ||
const balancedTxWithExUnits = this.setExecutionUnits(balancedTx, executionUnits); | ||
const rebalancedTx = this.rebalanceTx(balancedTxWithExUnits, txInputsInfo, { collateral, changeAddress }, { changeOutputIndex }); | ||
return rebalancedTx; | ||
try { | ||
const txInputsInfo = yield TxInputsInfo_1.default.init(transaction, inputs, utxos); | ||
const balancedTx = yield this.balanceTx(transaction, txInputsInfo, { utxos, collateral, changeAddress }, { feeUpperBound, mergeSignerOutputs }); | ||
const evaluation = yield exUnitsEvaluator.evaluate(balancedTx, txInputsInfo.toExportTxInputs()); | ||
if ((0, common_1.failed)(evaluation)) { | ||
return (0, common_1.fail)(`Execution units evaluation failed: ${evaluation.error}`); | ||
} | ||
const executionUnits = evaluation.value; | ||
const balancedTxWithExUnits = this.setExecutionUnits(balancedTx, executionUnits); | ||
const rebalancedTx = this.rebalanceTx(balancedTxWithExUnits, txInputsInfo, { collateral, changeAddress }, { changeOutputIndex }); | ||
return (0, common_1.success)(rebalancedTx); | ||
} | ||
catch (error) { | ||
return (0, common_1.fail)((0, common_1.show)(error)); | ||
} | ||
}); | ||
@@ -141,3 +150,3 @@ } | ||
const r = redeemers.get(i); | ||
const rTag = capitalizeFirstLetter((0, serLibPrinter_1.showRedeemerTag)(r.tag())); | ||
const rTag = r.tag().to_js_value(); | ||
const rIndex = Number(r.index().to_str()); | ||
@@ -211,7 +220,7 @@ for (let j = 0; j < execUnits.length; j += 1) { | ||
if (!burnedValue.is_zero()) { | ||
console.log("BURNED VALUE IN THE TX:", (0, serLibPrinter_1.showValue)(burnedValue)); | ||
console.log(`BURNED VALUE IN THE TX: ${burnedValue.to_json()}`); | ||
alreadyPaidValue = alreadyPaidValue.checked_sub(burnedValue); | ||
} | ||
} | ||
console.log("TOTAL VALUE ALREADY PAID BY INPUTS:", (0, serLibPrinter_1.showValue)(alreadyPaidValue)); | ||
console.log(`TOTAL VALUE ALREADY PAID BY INPUTS: ${alreadyPaidValue.to_json()}`); | ||
return alreadyPaidValue; | ||
@@ -236,6 +245,6 @@ } | ||
if (!mintedValue.is_zero()) { | ||
console.log("MINTED VALUE IN THE TX:", (0, serLibPrinter_1.showValue)(mintedValue)); | ||
console.log(`MINTED VALUE IN THE TX: ${mintedValue.to_json()}`); | ||
totalValueToPay = totalValueToPay.checked_sub(mintedValue); | ||
} | ||
console.log("TOTAL VALUE IN OUTPUTS + FEE:", (0, serLibPrinter_1.showValue)(totalValueToPay)); | ||
console.log(`TOTAL VALUE IN OUTPUTS + FEE: ${totalValueToPay.to_json()}`); | ||
} | ||
@@ -308,3 +317,3 @@ return totalValueToPay; | ||
const changeAddrInBech32 = this.S.Address.from_hex(changeAddress).to_bech32(); | ||
console.log(`PAYING ${(0, serLibPrinter_1.showValue)(change)} OF CHANGE TO ${changeAddrInBech32}`); | ||
console.log(`PAYING ${change.to_json()} OF CHANGE TO ${changeAddrInBech32}`); | ||
if (change.coin().compare(this.S.BigNum.from_str("2")) < 0) { | ||
@@ -334,3 +343,3 @@ // the change value is less than minAda so look for a suitable utxo to receive it | ||
} | ||
// if there are plutus scripts invovled in the tx, use the wallet's collaterals | ||
// if there are plutus scripts involved in the tx, use the wallet's collaterals | ||
if (txWitnessSet.plutus_scripts()) { | ||
@@ -445,3 +454,3 @@ // then there is the need to set the collateral | ||
else { | ||
console.log("RUNNING COIN SELECTION TO PAY:", (0, serLibPrinter_1.showValue)(mustBePaid)); | ||
console.log(`RUNNING COIN SELECTION TO PAY: ${mustBePaid.to_json()}`); | ||
CoinSelection_1.default.setProtocolParameters(minUtxo, linearFee.minFeeA.toString(), linearFee.minFeeB.toString(), maxTxSize.toString()); | ||
@@ -522,3 +531,3 @@ const selection = yield CoinSelection_1.default.randomImprove(candidateUtxosForCoinSelection, mustBePaid, 20, this.S); | ||
if (selectedOutput.address().to_hex() === changeAddress) { | ||
console.log("Change output:", (0, serLibPrinter_1.showTransactionOutput)(selectedOutput)); | ||
console.log(`Change output: ${selectedOutput.to_json()}`); | ||
return { | ||
@@ -550,3 +559,3 @@ changeOutput: selectedOutput, | ||
Change address of the wallet in bech32: ${this.S.Address.from_hex(changeAddress).to_bech32()} | ||
Outputs: ${(0, serLibPrinter_1.showTransactionOutputs)(outputs)} | ||
Outputs: ${outputs.to_json()} | ||
`); | ||
@@ -566,3 +575,3 @@ } | ||
const oldChangeOutputAmount = deepCopy(oldChangeOutput.amount(), this.S.Value); | ||
console.log("Old change output value:", (0, serLibPrinter_1.showValue)(oldChangeOutputAmount)); | ||
console.log(`Old change output value: ${oldChangeOutputAmount.to_json()}`); | ||
// Formula for calculating the new coin (i.e. lovelace) amount of the change output: | ||
@@ -574,3 +583,3 @@ // newCoin = oldCoin + (oldFee - newFee) | ||
newChangeValue.set_coin(newCoinAmount); | ||
console.log("New change output value:", (0, serLibPrinter_1.showValue)(newChangeValue)); | ||
console.log(`New change output value: ${newChangeValue.to_json()}`); | ||
return this.S.TransactionOutput.new(deepCopy(oldChangeOutput.address(), this.S.Address), newChangeValue); | ||
@@ -727,5 +736,4 @@ } | ||
} | ||
const capitalizeFirstLetter = (s) => s[0].toUpperCase() + s.slice(1); | ||
function deepCopy(objectToCopy, serLibClass) { | ||
return serLibClass.from_hex(objectToCopy.to_hex()); | ||
} |
@@ -124,3 +124,2 @@ "use strict"; | ||
var _a, _b, _c; | ||
console.log("utxo address:", utxo.output().address().to_bech32()); | ||
const datumHash = utxo.output().data_hash(); | ||
@@ -127,0 +126,0 @@ // eslint-disable-next-line @typescript-eslint/naming-convention |
@@ -8,5 +8,6 @@ /** | ||
import { Address, Hash64, Paginate, Result, TransactionUnspentOutput, TransactionWitnessSet, Value, WalletInfo } from "../common"; | ||
import { WalletAddress } from "../ContractEndpoints/types"; | ||
/** | ||
* Class that has the CIP-30 wallet methods plus some other useful ones for the usage of the | ||
* library itself, such as `getWalletInfo` and `signAndSubmit`. | ||
* library itself, such as `getWalletAddress`, `getWalletInfo` and `signAndSubmit`. | ||
*/ | ||
@@ -67,3 +68,2 @@ export default class CIP30WalletWrapper { | ||
submitTx(tx: string): Promise<Hash64>; | ||
getWalletId(): Promise<string>; | ||
/** | ||
@@ -76,2 +76,8 @@ * An utility functionality to get the wallet information in the format that the Balancer methods | ||
/** | ||
* Gets the **first one of the used addresses** of the CIP30 wallet and parses it into a | ||
* `WalletAddress` value. | ||
* @returns The first used address of the wallet as `WalletAddress`. | ||
*/ | ||
getWalletAddress(): Promise<WalletAddress>; | ||
/** | ||
* Functionality to sign and submit the given transaction. | ||
@@ -78,0 +84,0 @@ * @param transaction Transaction cbor. |
@@ -20,8 +20,8 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const blake2b_1 = __importDefault(require("blake2b")); | ||
const SerLibLoader_1 = __importDefault(require("../SerLibLoader")); | ||
const common_1 = require("../common"); | ||
const Address_1 = __importDefault(require("../Address")); | ||
/** | ||
* Class that has the CIP-30 wallet methods plus some other useful ones for the usage of the | ||
* library itself, such as `getWalletInfo` and `signAndSubmit`. | ||
* library itself, such as `getWalletAddress`, `getWalletInfo` and `signAndSubmit`. | ||
*/ | ||
@@ -128,12 +128,2 @@ class CIP30WalletWrapper { | ||
} | ||
getWalletId() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const walletUsedAddresses = yield this.wallet.getUsedAddresses(); | ||
const walletUnusedAddresses = yield this.wallet.getUnusedAddresses(); | ||
const addresses = walletUnusedAddresses.concat(walletUsedAddresses); | ||
return (0, blake2b_1.default)(20) | ||
.update(Buffer.from(addresses.join(""))) | ||
.digest("hex"); | ||
}); | ||
} | ||
/** | ||
@@ -159,2 +149,19 @@ * An utility functionality to get the wallet information in the format that the Balancer methods | ||
/** | ||
* Gets the **first one of the used addresses** of the CIP30 wallet and parses it into a | ||
* `WalletAddress` value. | ||
* @returns The first used address of the wallet as `WalletAddress`. | ||
*/ | ||
getWalletAddress() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const [addr] = yield this.wallet.getUsedAddresses(); | ||
const result = yield Address_1.default.fromHex(addr); | ||
if ((0, common_1.failed)(result)) { | ||
throw new Error(`An unexpected error happened: the first used address of the wallet was | ||
incorrectly parsed by the fromHex emthod of Address class.`); | ||
} | ||
const address = result.value; | ||
return address.toWalletAddress(); | ||
}); | ||
} | ||
/** | ||
* Functionality to sign and submit the given transaction. | ||
@@ -161,0 +168,0 @@ * @param transaction Transaction cbor. |
/** | ||
* @packageDocumentation | ||
* A class that uses the PAB to interact with contracts implemented with a | ||
* specific design pattern. This can be resumed like so | ||
* - `start` to initialize a new contract. | ||
* - `connect` to connect to an already existing contract instance. | ||
* specific design pattern. | ||
* In summary it provides the following functions | ||
* - `start` to activate a contract instance that yields a transaction. | ||
* - `connect` to activate a contract instance with no yield of transaction. | ||
* - `reload` to get the observable state defined by the contract in the Haskell off-chain code. | ||
@@ -18,32 +19,30 @@ * - `doOperation` for getting the unbalanced transaction of any other operation. | ||
* Create a new instance of a contract and obtain its unbalanced transaction. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callInit Name of the endpoint and its parameters to activate the contract or only the | ||
* @param call Name of the endpoint and its parameters to activate the contract or only the | ||
* parameters if the there's only one possible tag. | ||
* @param pabApi Api instance for this contract to use. | ||
* @param pabUrl Base URL of the PAB that will be used. | ||
* @returns A new instance of the class and an unbalanced transaction to initiate the contract. | ||
*/ | ||
static start(walletId: string, callInit: { | ||
endpointTag?: string; | ||
params: unknown; | ||
}, pabApi: PABApi): Promise<[ContractEndpoints, Result<ExportTx>]>; | ||
static start(pabUrl: string, call: { | ||
tag?: string; | ||
contents: unknown; | ||
}): Promise<[ContractEndpoints, Result<ExportTx>]>; | ||
/** | ||
* Connect to an already created instance of a contract on the blockchain. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callConnect Name of the endpoint and its parameters to connect to the contract or just | ||
* @param call Name of the endpoint and its parameters to connect to the contract or just | ||
* the parameters if there's only one possible tag. | ||
* @param pabApi PAB API instance for this contract to use. | ||
* @param pabUrl Base URL of the PAB that will be used. | ||
* @returns a new instance of the class. | ||
*/ | ||
static connect(walletId: string, callConnect: { | ||
endpointTag?: string; | ||
params: unknown; | ||
}, pabApi: PABApi): Promise<ContractEndpoints>; | ||
static connect(pabUrl: string, call: { | ||
tag?: string; | ||
contents: unknown; | ||
}): Promise<ContractEndpoints>; | ||
/** | ||
* Gets the observable state contained in the status of the PAB. | ||
* @param callReload Name of the reload endpoint and its required parameters. | ||
* @param call Name of the reload endpoint and its required parameters. | ||
* @returns The observable state if suceeded, or a string error otherwise. | ||
*/ | ||
reload(callReload: { | ||
endpointTag: string; | ||
params: unknown; | ||
reload(call: { | ||
tag: string; | ||
contents: unknown; | ||
}): Promise<Result<unknown>>; | ||
@@ -55,5 +54,5 @@ /** | ||
*/ | ||
doOperation(callEndpoint: { | ||
endpointTag: string; | ||
params: unknown; | ||
doOperation(call: { | ||
tag: string; | ||
contents: unknown; | ||
}): Promise<Result<ExportTx>>; | ||
@@ -60,0 +59,0 @@ /** |
@@ -7,5 +7,6 @@ "use strict"; | ||
* A class that uses the PAB to interact with contracts implemented with a | ||
* specific design pattern. This can be resumed like so | ||
* - `start` to initialize a new contract. | ||
* - `connect` to connect to an already existing contract instance. | ||
* specific design pattern. | ||
* In summary it provides the following functions | ||
* - `start` to activate a contract instance that yields a transaction. | ||
* - `connect` to activate a contract instance with no yield of transaction. | ||
* - `reload` to get the observable state defined by the contract in the Haskell off-chain code. | ||
@@ -23,3 +24,7 @@ * - `doOperation` for getting the unbalanced transaction of any other operation. | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const PABApi_1 = __importDefault(require("../PABApi")); | ||
const common_1 = require("../common"); | ||
@@ -33,11 +38,11 @@ class ContractEndpoints { | ||
* Create a new instance of a contract and obtain its unbalanced transaction. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callInit Name of the endpoint and its parameters to activate the contract or only the | ||
* @param call Name of the endpoint and its parameters to activate the contract or only the | ||
* parameters if the there's only one possible tag. | ||
* @param pabApi Api instance for this contract to use. | ||
* @param pabUrl Base URL of the PAB that will be used. | ||
* @returns A new instance of the class and an unbalanced transaction to initiate the contract. | ||
*/ | ||
static start(walletId, callInit, pabApi) { | ||
static start(pabUrl, call) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cid = yield pabApi.activate(walletId, callInit); | ||
const pabApi = new PABApi_1.default(pabUrl); | ||
const cid = yield pabApi.activate(call); | ||
const inst = new ContractEndpoints(pabApi, cid); | ||
@@ -50,13 +55,12 @@ const etx = yield inst.waitForNewExportTx(); | ||
* Connect to an already created instance of a contract on the blockchain. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callConnect Name of the endpoint and its parameters to connect to the contract or just | ||
* @param call Name of the endpoint and its parameters to connect to the contract or just | ||
* the parameters if there's only one possible tag. | ||
* @param pabApi PAB API instance for this contract to use. | ||
* @param pabUrl Base URL of the PAB that will be used. | ||
* @returns a new instance of the class. | ||
*/ | ||
static connect(walletId, callConnect, pabApi) { | ||
static connect(pabUrl, call) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cid = yield pabApi.activate(walletId, callConnect); | ||
const inst = new ContractEndpoints(pabApi, cid); | ||
return inst; | ||
const pabApi = new PABApi_1.default(pabUrl); | ||
const cid = yield pabApi.activate(call); | ||
return new ContractEndpoints(pabApi, cid); | ||
}); | ||
@@ -66,9 +70,10 @@ } | ||
* Gets the observable state contained in the status of the PAB. | ||
* @param callReload Name of the reload endpoint and its required parameters. | ||
* @param call Name of the reload endpoint and its required parameters. | ||
* @returns The observable state if suceeded, or a string error otherwise. | ||
*/ | ||
reload(callReload) { | ||
reload(call) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { tag, contents } = call; | ||
const oldStatus = yield this.pabApi.status(this.contractId); | ||
yield this.pabApi.endpoint(this.contractId, callReload); | ||
yield this.pabApi.endpoint(this.contractId, tag, contents); | ||
const observableState = yield this.getObservableState(oldStatus); | ||
@@ -83,6 +88,7 @@ return observableState; | ||
*/ | ||
doOperation(callEndpoint) { | ||
doOperation(call) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { tag, contents } = call; | ||
const oldStatus = yield this.pabApi.status(this.contractId); | ||
yield this.pabApi.endpoint(this.contractId, callEndpoint); | ||
yield this.pabApi.endpoint(this.contractId, tag, contents); | ||
const etx = this.waitForNewExportTx(oldStatus); | ||
@@ -89,0 +95,0 @@ return etx; |
@@ -5,16 +5,17 @@ /** | ||
*/ | ||
import Address from "./Address"; | ||
import AssetClass from "./PABApi/types/AssetClass"; | ||
import Balancer from "./Balancer"; | ||
import CIP30WalletWrapper from "./CIP30WalletWrapper"; | ||
import Balancer from "./Balancer"; | ||
import ContractEndpoints from "./ContractEndpoints"; | ||
import PABApi from "./PABApi"; | ||
import Value from "./PABApi/types/Value"; | ||
import AssetClass from "./PABApi/types/AssetClass"; | ||
import SerLibLoader from "./SerLibLoader"; | ||
import TxOutRef from "./PABApi/types/TxOutRef"; | ||
import { Plutus } from "./PABApi/types/Plutus"; | ||
import ContractEndpoints from "./ContractEndpoints"; | ||
import WalletAddress from "./ContractEndpoints/WalletAddress"; | ||
import TxBudgetAPI from "./TxBudgetApi"; | ||
import SerLibLoader from "./SerLibLoader"; | ||
import TxInputsInfo from "./Balancer/TxInputsInfo"; | ||
import { getWalletInitialAPI, getProtocolParamsFromBlockfrost } from "./utilities"; | ||
import Value from "./PABApi/types/Value"; | ||
import { Plutus } from "./PABApi/types/Plutus"; | ||
import { getWalletInitialAPI, getProtocolParamsFromBlockfrost, setMetadataMessage } from "./utilities"; | ||
import { failed, succeeded } from "./common"; | ||
export { CIP30WalletWrapper, PABApi, ContractEndpoints, TxBudgetAPI, Balancer, TxInputsInfo, SerLibLoader, Value, AssetClass, TxOutRef, WalletAddress, Plutus, getWalletInitialAPI, getProtocolParamsFromBlockfrost, succeeded, failed, }; | ||
import { WalletAddress } from "./ContractEndpoints/types"; | ||
export { CIP30WalletWrapper, PABApi, ContractEndpoints, TxBudgetAPI, Balancer, Address, TxInputsInfo, SerLibLoader, Value, AssetClass, TxOutRef, WalletAddress, Plutus, getWalletInitialAPI, getProtocolParamsFromBlockfrost, setMetadataMessage, succeeded, failed, }; |
@@ -10,32 +10,33 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.failed = exports.succeeded = exports.getProtocolParamsFromBlockfrost = exports.getWalletInitialAPI = exports.Plutus = exports.WalletAddress = exports.TxOutRef = exports.AssetClass = exports.Value = exports.SerLibLoader = exports.TxInputsInfo = exports.Balancer = exports.TxBudgetAPI = exports.ContractEndpoints = exports.PABApi = exports.CIP30WalletWrapper = void 0; | ||
exports.failed = exports.succeeded = exports.setMetadataMessage = exports.getProtocolParamsFromBlockfrost = exports.getWalletInitialAPI = exports.Plutus = exports.TxOutRef = exports.AssetClass = exports.Value = exports.SerLibLoader = exports.TxInputsInfo = exports.Address = exports.Balancer = exports.TxBudgetAPI = exports.ContractEndpoints = exports.PABApi = exports.CIP30WalletWrapper = void 0; | ||
const Address_1 = __importDefault(require("./Address")); | ||
exports.Address = Address_1.default; | ||
const AssetClass_1 = __importDefault(require("./PABApi/types/AssetClass")); | ||
exports.AssetClass = AssetClass_1.default; | ||
const Balancer_1 = __importDefault(require("./Balancer")); | ||
exports.Balancer = Balancer_1.default; | ||
const CIP30WalletWrapper_1 = __importDefault(require("./CIP30WalletWrapper")); | ||
exports.CIP30WalletWrapper = CIP30WalletWrapper_1.default; | ||
const Balancer_1 = __importDefault(require("./Balancer")); | ||
exports.Balancer = Balancer_1.default; | ||
const ContractEndpoints_1 = __importDefault(require("./ContractEndpoints")); | ||
exports.ContractEndpoints = ContractEndpoints_1.default; | ||
const PABApi_1 = __importDefault(require("./PABApi")); | ||
exports.PABApi = PABApi_1.default; | ||
const Value_1 = __importDefault(require("./PABApi/types/Value")); | ||
exports.Value = Value_1.default; | ||
const AssetClass_1 = __importDefault(require("./PABApi/types/AssetClass")); | ||
exports.AssetClass = AssetClass_1.default; | ||
const SerLibLoader_1 = __importDefault(require("./SerLibLoader")); | ||
exports.SerLibLoader = SerLibLoader_1.default; | ||
const TxOutRef_1 = __importDefault(require("./PABApi/types/TxOutRef")); | ||
exports.TxOutRef = TxOutRef_1.default; | ||
const Plutus_1 = require("./PABApi/types/Plutus"); | ||
Object.defineProperty(exports, "Plutus", { enumerable: true, get: function () { return Plutus_1.Plutus; } }); | ||
const ContractEndpoints_1 = __importDefault(require("./ContractEndpoints")); | ||
exports.ContractEndpoints = ContractEndpoints_1.default; | ||
const WalletAddress_1 = __importDefault(require("./ContractEndpoints/WalletAddress")); | ||
exports.WalletAddress = WalletAddress_1.default; | ||
const TxBudgetApi_1 = __importDefault(require("./TxBudgetApi")); | ||
exports.TxBudgetAPI = TxBudgetApi_1.default; | ||
const SerLibLoader_1 = __importDefault(require("./SerLibLoader")); | ||
exports.SerLibLoader = SerLibLoader_1.default; | ||
const TxInputsInfo_1 = __importDefault(require("./Balancer/TxInputsInfo")); | ||
exports.TxInputsInfo = TxInputsInfo_1.default; | ||
const Value_1 = __importDefault(require("./PABApi/types/Value")); | ||
exports.Value = Value_1.default; | ||
const Plutus_1 = require("./PABApi/types/Plutus"); | ||
Object.defineProperty(exports, "Plutus", { enumerable: true, get: function () { return Plutus_1.Plutus; } }); | ||
const utilities_1 = require("./utilities"); | ||
Object.defineProperty(exports, "getWalletInitialAPI", { enumerable: true, get: function () { return utilities_1.getWalletInitialAPI; } }); | ||
Object.defineProperty(exports, "getProtocolParamsFromBlockfrost", { enumerable: true, get: function () { return utilities_1.getProtocolParamsFromBlockfrost; } }); | ||
Object.defineProperty(exports, "setMetadataMessage", { enumerable: true, get: function () { return utilities_1.setMetadataMessage; } }); | ||
const common_1 = require("./common"); | ||
Object.defineProperty(exports, "failed", { enumerable: true, get: function () { return common_1.failed; } }); | ||
Object.defineProperty(exports, "succeeded", { enumerable: true, get: function () { return common_1.succeeded; } }); |
@@ -18,10 +18,9 @@ /** | ||
* Wrapper of the activate endpoint of the PAB. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callActivate Name of the endpoint and its parameters for activate the contract. If | ||
* @param call Name of the endpoint and its parameters for activate the contract. If | ||
* there's only one possible tag name for activating, it receives *only* the parameters. | ||
* @returns A contract ID to the activated contract. | ||
*/ | ||
activate(walletId: string, callActivate: { | ||
endpointTag?: string; | ||
params: unknown; | ||
activate(call: { | ||
tag?: string; | ||
contents: unknown; | ||
}): Promise<ContractId>; | ||
@@ -36,8 +35,6 @@ /** | ||
* @param contractId Id of the instance of the contract on which the endpoint is being called. | ||
* @param callEndpoint Name of the endpoint being called and its parameters. | ||
* @param tag Name of the endpoint to call. | ||
* @param contents Parameters of the endpoint. | ||
*/ | ||
endpoint(contractId: ContractId, callEndpoint: { | ||
endpointTag: string; | ||
params: unknown; | ||
}): Promise<void>; | ||
endpoint(contractId: ContractId, tag: string, contents: unknown): Promise<void>; | ||
/** | ||
@@ -44,0 +41,0 @@ * Obtains and returns the status of a contract. |
@@ -33,14 +33,13 @@ "use strict"; | ||
* Wrapper of the activate endpoint of the PAB. | ||
* @param walletId Id of the wallet being used to activate the contract. | ||
* @param callActivate Name of the endpoint and its parameters for activate the contract. If | ||
* @param call Name of the endpoint and its parameters for activate the contract. If | ||
* there's only one possible tag name for activating, it receives *only* the parameters. | ||
* @returns A contract ID to the activated contract. | ||
*/ | ||
activate(walletId, callActivate) { | ||
activate(call) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { tag, contents } = call; | ||
const dummyWalletId = "0".repeat(40); | ||
const params = { | ||
caID: callActivate.endpointTag !== undefined | ||
? { tag: callActivate.endpointTag, contents: callActivate.params } | ||
: callActivate.params, | ||
caWallet: { getWalletId: walletId }, | ||
caID: tag !== undefined ? { tag, contents } : contents, | ||
caWallet: { getWalletId: dummyWalletId }, | ||
}; | ||
@@ -63,7 +62,8 @@ const response = yield axios_1.default.post(`${this.pabUrl}/contract/activate`, JSON.stringify(params), { headers: { "Content-Type": "application/json" } }); | ||
* @param contractId Id of the instance of the contract on which the endpoint is being called. | ||
* @param callEndpoint Name of the endpoint being called and its parameters. | ||
* @param tag Name of the endpoint to call. | ||
* @param contents Parameters of the endpoint. | ||
*/ | ||
endpoint(contractId, callEndpoint) { | ||
endpoint(contractId, tag, contents) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield axios_1.default.post(`${this.pabUrl}/contract/instance/${contractId}/endpoint/${callEndpoint.endpointTag}`, JSON.stringify(callEndpoint.params), { headers: { "Content-Type": "application/json" } }); | ||
yield axios_1.default.post(`${this.pabUrl}/contract/instance/${contractId}/endpoint/${tag}`, JSON.stringify(contents), { headers: { "Content-Type": "application/json" } }); | ||
}); | ||
@@ -70,0 +70,0 @@ } |
@@ -33,2 +33,8 @@ /** | ||
const singleton: (cs: CurrencySymbol, tn: TokenName, quantity: number) => Value; | ||
type PubKeyHash = { | ||
getPubKeyHash: string; | ||
}; | ||
const mkPubKeyHash: (kh: string) => { | ||
getPubKeyHash: string; | ||
}; | ||
function isCurrencySymbol(cs: unknown): cs is CurrencySymbol; | ||
@@ -35,0 +41,0 @@ function isTokenName(tn: unknown): tn is TokenName; |
@@ -18,2 +18,3 @@ "use strict"; | ||
Plutus.singleton = (cs, tn, quantity) => (Plutus.mkValue([[cs, [[tn, quantity]]]])); | ||
Plutus.mkPubKeyHash = (kh) => ({ getPubKeyHash: kh }); | ||
// Validation functions | ||
@@ -20,0 +21,0 @@ function isCurrencySymbol(cs) { |
@@ -35,3 +35,3 @@ /** | ||
/** | ||
* Endpoint to estimate the execution units of each redeemer of the given transaction. | ||
* Endpoint to evaluate the execution units of each redeemer of the given transaction. | ||
* @param tx The transaction cbor. | ||
@@ -42,4 +42,4 @@ * @param inputsInfo Complete information about the inputs of the transaction. | ||
*/ | ||
estimate(tx: string, inputsInfo: ExportTxInput[]): Promise<Result<Array<[Redeemer, ExecutionUnits]>>>; | ||
evaluate(tx: string, inputsInfo: ExportTxInput[]): Promise<Result<Array<[Redeemer, ExecutionUnits]>>>; | ||
} | ||
export {}; |
@@ -37,6 +37,4 @@ "use strict"; | ||
} | ||
// // GET request method for checking if the service is up | ||
// public async health() { ... } | ||
/** | ||
* Endpoint to estimate the execution units of each redeemer of the given transaction. | ||
* Endpoint to evaluate the execution units of each redeemer of the given transaction. | ||
* @param tx The transaction cbor. | ||
@@ -47,3 +45,3 @@ * @param inputsInfo Complete information about the inputs of the transaction. | ||
*/ | ||
estimate(tx, inputsInfo) { | ||
evaluate(tx, inputsInfo) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -53,7 +51,7 @@ const estimParam = { | ||
inputs: inputsInfo, | ||
redeemers: [], // the estimator doesn't need the redeemers, but the placeholder is needed | ||
redeemers: [], // the service doesn't need the redeemers, but the placeholder is needed | ||
}; | ||
let estimation; | ||
let evaluation; | ||
try { | ||
estimation = (yield axios_1.default.post(`${this.config.baseUrl}/estimate`, JSON.stringify(estimParam), { | ||
evaluation = (yield axios_1.default.post(`${this.config.baseUrl}/evaluate`, JSON.stringify(estimParam), { | ||
headers: { "Content-Type": "application/json" }, | ||
@@ -66,8 +64,8 @@ timeout: this.config.timeout, | ||
} | ||
if (estimation.Left) { | ||
return (0, common_1.fail)(JSON.stringify(estimation.Left)); | ||
if (evaluation.Left) { | ||
return (0, common_1.fail)(JSON.stringify(evaluation.Left)); | ||
} | ||
if (estimation.Right) { | ||
if (evaluation.Right) { | ||
const res = []; | ||
const ent = Object.entries(estimation.Right); | ||
const ent = Object.entries(evaluation.Right); | ||
for (let t = 0; t < ent.length; t += 1) { | ||
@@ -85,3 +83,3 @@ const [k, e] = ent[t]; | ||
tmpUnit = { | ||
mem: 16000000, | ||
mem: 14000000, | ||
cpu: 10000000000, | ||
@@ -99,3 +97,3 @@ }; | ||
} | ||
return (0, common_1.fail)("Unkown estimator failure"); | ||
return (0, common_1.fail)("Unknown budget service failure"); | ||
}); | ||
@@ -102,0 +100,0 @@ } |
@@ -44,2 +44,19 @@ /** | ||
export declare function getWalletInitialAPI(window: NeededWindow, walletName: SupportedWallet): CIP30WalletInitialAPI; | ||
/** | ||
* Adds a message as metadata into the given transaction with the schema defined in CIP20. | ||
* See https://cips.cardano.org/cips/cip20/#abstract. | ||
* | ||
* **IMPORTANT NOTE**: this function updates the transaction body by setting the field 7: | ||
* https://github.com/input-output-hk/cardano-ledger/blob/583a13e80336666979ad0c2a98375987bee950f3/eras/babbage/test-suite/cddl-files/babbage.cddl#L61 | ||
* and also sets the auxiliary data field | ||
* https://github.com/input-output-hk/cardano-ledger/blob/583a13e80336666979ad0c2a98375987bee950f3/eras/babbage/test-suite/cddl-files/babbage.cddl#L17 | ||
* | ||
* So, this should be done **before** the rebalancing step and the calculation of the tx execution | ||
* units since the transaction fee will go up a little bit because of the tx being a few bytes | ||
* bigger. | ||
* @param transaction The transaction cbor. | ||
* @param msg The message as a string to put into the metadata. | ||
* @returns The transaction cbor with the metadata message and hash fields set. | ||
*/ | ||
export declare function setMetadataMessage(transaction: string, msg: string): Promise<string>; | ||
export {}; |
@@ -19,4 +19,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getWalletInitialAPI = exports.getProtocolParamsFromBlockfrost = void 0; | ||
exports.setMetadataMessage = exports.getWalletInitialAPI = exports.getProtocolParamsFromBlockfrost = void 0; | ||
const axios_1 = __importDefault(require("axios")); | ||
const SerLibLoader_1 = __importDefault(require("./SerLibLoader")); | ||
/** | ||
@@ -67,1 +68,54 @@ * Utility function for getting the protocol parameters from blockfrost API, which are needed | ||
exports.getWalletInitialAPI = getWalletInitialAPI; | ||
/** | ||
* Adds a message as metadata into the given transaction with the schema defined in CIP20. | ||
* See https://cips.cardano.org/cips/cip20/#abstract. | ||
* | ||
* **IMPORTANT NOTE**: this function updates the transaction body by setting the field 7: | ||
* https://github.com/input-output-hk/cardano-ledger/blob/583a13e80336666979ad0c2a98375987bee950f3/eras/babbage/test-suite/cddl-files/babbage.cddl#L61 | ||
* and also sets the auxiliary data field | ||
* https://github.com/input-output-hk/cardano-ledger/blob/583a13e80336666979ad0c2a98375987bee950f3/eras/babbage/test-suite/cddl-files/babbage.cddl#L17 | ||
* | ||
* So, this should be done **before** the rebalancing step and the calculation of the tx execution | ||
* units since the transaction fee will go up a little bit because of the tx being a few bytes | ||
* bigger. | ||
* @param transaction The transaction cbor. | ||
* @param msg The message as a string to put into the metadata. | ||
* @returns The transaction cbor with the metadata message and hash fields set. | ||
*/ | ||
function setMetadataMessage(transaction, msg) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!msg) { | ||
return transaction; | ||
} | ||
yield SerLibLoader_1.default.load(); | ||
const S = SerLibLoader_1.default.lib; | ||
const tx = S.Transaction.from_hex(transaction); | ||
const metadataText = S.TransactionMetadatum.new_text(msg); | ||
// ${metadata} | ||
const metadataList = S.MetadataList.new(); | ||
metadataList.add(metadataText); | ||
const metadataIntoList = S.TransactionMetadatum.new_list(metadataList); | ||
// [ ${metadata} ] | ||
const metadataMap = S.MetadataMap.new(); | ||
metadataMap.insert_str("msg", metadataIntoList); | ||
const metadataIntoMap = S.TransactionMetadatum.new_map(metadataMap); | ||
// { msg: [ ${metadata} ] } | ||
const txMetadata = S.GeneralTransactionMetadata.new(); | ||
txMetadata.insert(S.BigNum.from_str("674"), metadataIntoMap); | ||
// { | ||
// "key": "674", | ||
// "json": { msg: [ ${metadata} ] } | ||
// "bytes": ... | ||
// } | ||
let auxData = tx.auxiliary_data(); | ||
if (!auxData) { | ||
auxData = S.AuxiliaryData.new(); | ||
} | ||
auxData.set_metadata(txMetadata); | ||
const auxDataHash = S.hash_auxiliary_data(auxData); | ||
const newTxBody = tx.body(); | ||
newTxBody.set_auxiliary_data_hash(auxDataHash); | ||
return S.Transaction.new(newTxBody, tx.witness_set(), auxData).to_hex(); | ||
}); | ||
} | ||
exports.setMetadataMessage = setMetadataMessage; |
{ | ||
"name": "cardano-pab-client", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "A set of tools to develop frontends that interact with the Plutus Application Backend.", | ||
@@ -16,3 +16,3 @@ "author": "Plank", | ||
"prepublish": "rm -rf dist && npm run build", | ||
"generate-docs": "npx typedoc --plugin typedoc-plugin-markdown --plugin typedoc-plugin-missing-exports" | ||
"generate-docs": "npx typedoc --plugin typedoc-plugin-missing-exports" | ||
}, | ||
@@ -45,3 +45,2 @@ "repository": { | ||
"typedoc": "^0.23.22", | ||
"typedoc-plugin-markdown": "^3.14.0", | ||
"typedoc-plugin-missing-exports": "^1.0.0", | ||
@@ -52,5 +51,4 @@ "typescript": "^4.8.4" | ||
"@emurgo/cardano-serialization-lib-browser": "11.1.0", | ||
"axios": "^1.1.3", | ||
"blake2b": "^2.1.4" | ||
"axios": "^1.1.3" | ||
} | ||
} |
121
README.md
@@ -13,3 +13,3 @@ # Cardano PAB client library | ||
```typescript | ||
function startContract(): ContractEndpoints { | ||
function startContract(): ContractEndpoints | undefined { | ||
// NOTE: all the modules of this library MUST be imported dynamically like this | ||
@@ -20,2 +20,3 @@ const { | ||
getProtocolParamsFromBlockfrost, | ||
failed, | ||
} = await import("cardano-pab-client"); | ||
@@ -35,81 +36,46 @@ | ||
// Try to get unbalanced transaction from PAB | ||
const walletId = await wallet.getWalletId(); | ||
const pabApi = new PABApi("http://localhost:9080"); | ||
const [endpoints, pabResponse] = await ContractEndpoints.start( | ||
walletId, | ||
pabUrl, | ||
{ endpointTag: "Init", params: [] }, | ||
pabApi, | ||
); | ||
if (!succeeded(pabResponse)) { | ||
if (failed(pabResponse)) { | ||
alert( | ||
`Didn't got the unbalanced transaction from the PAB. Error: ${pabResponse.error}` | ||
`Didn't get the unbalanced transaction from the PAB. Error: ${pabResponse.error}` | ||
); | ||
} else { | ||
// the pab yielded the unbalanced transaction. balance, sign and submit it. | ||
const etx = pabResponse.value; | ||
return; | ||
} | ||
// the pab yielded the unbalanced transaction. balance, sign and submit it. | ||
const etx = pabResponse.value; | ||
const walletInfo = await wallet.getWalletInfo(); | ||
const txBudgetApi = new TxBudgetAPI({ | ||
baseUrl: "http//:localhost:3001", | ||
timeout: 10000, | ||
}); | ||
const walletInfo = await wallet.getWalletInfo(); | ||
const txBudgetApi = new TxBudgetAPI({ | ||
baseUrl: "http//:localhost:3001", | ||
timeout: 10000, | ||
}); | ||
const fullyBalancedTx = await balancer.fullBalanceTx( | ||
etx, | ||
walletInfo, | ||
// configuration for the balanceTx and rebalanceTx methods which are interally | ||
// used by this method | ||
{ feeUpperBound: 1000000, mergeSignerOutputs: false }, | ||
// a high-order function that exposes the balanced tx and the inputs info so to | ||
// calculate the executions units, which are then set in the transaction and | ||
// goes to the rebalancing step | ||
async (balancedTx, inputsInfo) => { | ||
const txBudgetResponse = await txBudgetApi.estimate(balancedTx, inputsInfo); | ||
if (succeeded(txBudgetResponse)) { | ||
const units = txBudgetResponse.value; | ||
return units; | ||
} | ||
// if the tx budget service fails or it isn't available, | ||
// fallback to hardcoded units | ||
// directly use the serialization library is useful here | ||
// must be dynamically imported too! | ||
const { SerLibLoader } = await import("cardano-pab-client"); | ||
await SerLibLoader.load(); | ||
const S = SerLibLoader.lib; | ||
// parse the transaction cbor into a nice format | ||
const tx = S.Transaction.from_hex(balancedTx).to_js_value(); | ||
// ... here you have all the info of the transaction | ||
// in particular, access to the redeemers like so | ||
const { redeemers } = tx.witness_set; | ||
// also, have the complete information about the inputs (not only | ||
// the references) in the inputsInfo object | ||
if (redeemers) { | ||
redeemers.forEach((r: S.RedeemerJSON) => /*...*/); | ||
// do stuff... | ||
return [ | ||
[{ tag: "Mint", index: 0 }, { mem: 4000000, cpu: 1500000000 }], | ||
[{ tag: "Spend", index: 2 }, { mem: 6000000, cpu: 1800000000 }], | ||
// ... | ||
]; | ||
} | ||
// no redeemers, so no hardcoded units are needed. | ||
return []; | ||
}, | ||
); | ||
// print to the console the fully balanced tx cbor for debugging purposes | ||
console.log(`Balanced tx: ${fullyBalancedTx}`); | ||
// now that the transaction is balanced, sign and submit it with the wallet | ||
const response = await wallet.signAndSubmit(fullyBalancedTx); | ||
if (succeeded(response)) { | ||
const txHash = response.value; | ||
alert(`Start suceeded. Tx hash: ${txHash}`); | ||
} else { | ||
alert(`Start failed when trying to submit it. Error: ${response.error}`); | ||
} | ||
const balancerResponse = await balancer.fullBalanceTx( | ||
etx, | ||
walletInfo, | ||
// configuration for the balanceTx and rebalanceTx methods which are interally | ||
// used by this method | ||
{ feeUpperBound: 1000000, mergeSignerOutputs: false }, | ||
// the tx budget service api that will calculate the execution units of the redeemers of the tx | ||
txBudgetApi, | ||
); | ||
if (failed(balancerResponse)) { | ||
alert(`Balancer failed with error: ${balancerResponse.error}`); | ||
return; | ||
} | ||
const fullyBalancedTx = balancerResponse.value; | ||
// print to the console the fully balanced tx cbor for debugging purposes | ||
console.log(`Balanced tx: ${fullyBalancedTx}`); | ||
// now that the transaction is balanced, sign and submit it with the wallet | ||
const walletResponse = await wallet.signAndSubmit(fullyBalancedTx); | ||
if (failed(walletResponse)) { | ||
alert(`Start failed when trying to submit it. Error: ${walletResponse.error}`); | ||
return; | ||
} | ||
const txHash = response.value; | ||
alert(`Start suceeded. Tx hash: ${txHash}`); | ||
// the ContractEndpoints instance is connected to the PAB, so we can return it to | ||
@@ -140,2 +106,13 @@ // continue doing operations with it. | ||
// ... | ||
``` | ||
``` | ||
## Codebase docs as website | ||
They are a set of HTMLs, so to run them into a website you could go to the `docs/` folder and run the following commands | ||
```bash | ||
docker build --tag docs-site:latest . | ||
docker run -it --name docs -p 5000:80 docs-site:latest | ||
``` | ||
That will run the docs at http://localhost:5000. |
2
14
189794
37
3824
115
- Removedblake2b@^2.1.4
- Removedb4a@1.6.7(transitive)
- Removedblake2b@2.1.4(transitive)
- Removedblake2b-wasm@2.4.0(transitive)
- Removednanoassert@2.0.0(transitive)