Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client-utils #992

Merged
merged 44 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
364caa9
feat(client-utils): wip, adds @kadena/client-utils as shared utility …
alber70g Sep 22, 2023
ab63086
feat(client): add asyncPipe
javadkh2 Sep 27, 2023
c2c022f
feat(client-example): using async pipe
javadkh2 Sep 27, 2023
f5228fb
feat: uodate examples
javadkh2 Sep 27, 2023
f335a77
feat: update fp
javadkh2 Sep 27, 2023
5e67c2a
fix: type issues
javadkh2 Oct 3, 2023
4a7da19
feat: rich-clients
javadkh2 Oct 3, 2023
75e05d2
feat(client): utils
javadkh2 Oct 4, 2023
2a7d2d7
feat: add some utils
javadkh2 Oct 5, 2023
0dac48f
feat: event type
javadkh2 Oct 10, 2023
511f039
refactor(client-utils): use EventTarget instead of EventEmitter
javadkh2 Oct 10, 2023
58fec7a
refactor: example
javadkh2 Oct 10, 2023
4c240d6
refactor: rename files
javadkh2 Oct 10, 2023
2ce69fb
refactor(WIP): move utils to the client-utils
javadkh2 Oct 10, 2023
3c1e1e6
fix: config
javadkh2 Oct 10, 2023
37d0a81
fix: client-examples
javadkh2 Oct 10, 2023
bd88760
chore: clean up
javadkh2 Oct 10, 2023
fafdb30
chore: clean up
javadkh2 Oct 10, 2023
f4b79dd
test(client-utils): integration test
javadkh2 Oct 10, 2023
bee11f4
test: integration test
javadkh2 Oct 11, 2023
2570cce
chore: clean up
javadkh2 Oct 11, 2023
aba62b2
fix: format
javadkh2 Oct 11, 2023
7e965e0
chore: add integration test to the github workflo
javadkh2 Oct 11, 2023
58bf994
chore: clean up
javadkh2 Oct 12, 2023
b91a170
chore(client-utils): lib path
javadkh2 Oct 16, 2023
af0f290
refactor(client-utils): rename module
javadkh2 Oct 16, 2023
81b28a9
chore: run liter
javadkh2 Oct 16, 2023
ca0429b
chore: install node/type
javadkh2 Oct 16, 2023
0961df0
chore: tsconfig
javadkh2 Oct 16, 2023
d5d7e08
fix(client-utils): build script
javadkh2 Oct 16, 2023
21ea44b
chore: dependency
javadkh2 Oct 16, 2023
9cf159a
refactor: getHostUrl
javadkh2 Oct 16, 2023
396bc12
chore: types
javadkh2 Oct 16, 2023
4b4f549
chore: format
javadkh2 Oct 16, 2023
79b7a6f
chore(client-utils): api extractor
javadkh2 Oct 17, 2023
1f952bb
refactor(client-utils): varibale names
javadkh2 Oct 24, 2023
0d64b08
chore: use vitest
javadkh2 Oct 25, 2023
69a5811
chore: clean up
javadkh2 Oct 25, 2023
27810c4
chore: clean up
javadkh2 Oct 25, 2023
d0d0084
docs: add todo
javadkh2 Oct 25, 2023
8324107
docs: add contents
alber70g Oct 25, 2023
d04d379
chore: add changelog for @kadena/client
alber70g Oct 25, 2023
daa3912
chore: fix mismatched package versions
alber70g Oct 25, 2023
0d3daad
chore: format linter
alber70g Oct 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/two-dragons-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@kadena/client': patch
---

Expose two new functions:
- `getHostUrl` to use with `@kadena/client-utils` package
- `submitOne` to make piping easier. As the piped arguments can be ambiguous
(array or single transaction)
7 changes: 5 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ jobs:
run: pnpm install

- name: Build client and dependencies
run: pnpm turbo build --filter @kadena/client
run: pnpm turbo build --filter @kadena/client-utils

- name: run integration tests
- name: run client integration tests
run: pnpm run test:integration --filter @kadena/client

- name: run client-utils integration tests
run: pnpm run test:integration --filter @kadena/client-utils
4 changes: 4 additions & 0 deletions packages/libs/client-examples/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@ require('@rushstack/eslint-config/patch/modern-module-resolution');

module.exports = {
extends: ['@kadena-dev/eslint-config/profile/lib'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@rushstack/typedef-var': 'off',
},
parserOptions: { tsconfigRootDir: __dirname },
};
1 change: 1 addition & 0 deletions packages/libs/client-examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"@kadena/chainweb-node-client": "workspace:*",
"@kadena/client": "workspace:*",
"@kadena/client-utils": "workspace:*",
"@kadena/pactjs": "workspace:*"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
readKeyset,
signWithChainweaver,
} from '@kadena/client';
import { asyncPipe } from '@kadena/client-utils/core';
import {
addKeyset,
addSigner,
Expand All @@ -16,8 +17,9 @@ import {
} from '@kadena/client/fp';
import { isSignedCommand } from '@kadena/pactjs';
import type { ChainId } from '@kadena/types';
import { listen, pollCreateSpv, submit } from '../util/client';
import { asyncPipe, inspect } from '../util/fp-helpers';

import { listen, pollCreateSpv, submitOne } from '../util/client';
import { inspect } from '../util/fp-helpers';
import { keyFromAccount } from '../util/keyFromAccount';

interface IAccount {
Expand All @@ -38,7 +40,6 @@ const receiverAccount: string =

const NETWORK_ID: string = 'testnet04';

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function startInTheFirstChain(from: IAccount, to: IAccount, amount: string) {
return composePactCommand(
execution(
Expand Down Expand Up @@ -71,7 +72,6 @@ function startInTheFirstChain(from: IAccount, to: IAccount, amount: string) {
);
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const finishInTheTargetChain = (
targetChainId: ChainId,
gasPayer: string = 'kadena-xchain-gas',
Expand Down Expand Up @@ -99,34 +99,35 @@ const finishInTheTargetChain = (
);
};

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const rejectIfFailed = (message: string) => (response: ICommandResult) =>
response.result.status === 'failure'
? Promise.reject(new Error(message))
: response;

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async function doCrossChainTransfer(
from: IAccount,
to: IAccount,
amount: string,
) {
return asyncPipe(
const debit = asyncPipe(
startInTheFirstChain(from, to, amount),
createTransaction,
inspect('TX_CREATED'),
signWithChainweaver,
inspect('TX_SIGNED'),
(command) =>
isSignedCommand(command) ? command : Promise.reject('CMD_NOT_SIGNED'),
submit,
submitOne,
inspect('TX_SUBMITTED'),
listen,
inspect('TX_RESULT'),
rejectIfFailed('DEBIT_REJECTED'),
);

const credit = asyncPipe(
(status: ICommandResult) =>
Promise.all([
status.continuation?.pactId,
status.continuation!.pactId,
pollCreateSpv(
{
requestKey: status.reqKey,
Expand All @@ -135,17 +136,19 @@ async function doCrossChainTransfer(
},
to.chainId,
),
]),
] as const),
inspect('SPV_CREATED'),
finishInTheTargetChain(to.chainId),
alber70g marked this conversation as resolved.
Show resolved Hide resolved
createTransaction,
inspect('CONT_CREATED'),
submit,
submitOne,
inspect('CONT_SUBMITTED'),
listen,
inspect('CONT_RESULT'),
rejectIfFailed('CREDIT REJECTED'),
)({});
);

return asyncPipe(debit, credit)({});
}

const from: IAccount = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import type { ChainId } from '@kadena/client';
import {
createTransaction,
isSignedTransaction,
Pact,
signWithChainweaver,
} from '@kadena/client';
import { createTransaction, Pact, signWithChainweaver } from '@kadena/client';
import { asyncPipe } from '@kadena/client-utils/core';
import {
addSigner,
composePactCommand,
execution,
setMeta,
setNetworkId,
} from '@kadena/client/fp';
import { pollStatus, preflight, submit } from '../util/client';
import { asyncPipe, inspect } from '../util/fp-helpers';

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
import { pollStatus, submitOne } from '../util/client';
import { inspect, safeSign } from '../util/fp-helpers';

const getTransferCommand = ({
sender,
receiver,
Expand Down Expand Up @@ -45,7 +41,6 @@ const getTransferCommand = ({
setNetworkId(networkId),
);

// eslint-disable-next-line @rushstack/typedef-var
const doTransfer = asyncPipe(
// you can edit the command form the input or complete it if it needs more information
// for example hear we add gasLimit and gasPrice
Expand All @@ -57,13 +52,8 @@ const doTransfer = asyncPipe(
),
inspect('command'),
createTransaction,
signWithChainweaver,
(tr) => (isSignedTransaction(tr) ? tr : Promise.reject('TR_NOT_SIGNED')),
// do preflight first to check if everything is ok without paying gas
(tr) => preflight(tr).then((res) => [tr, res]),
([tr, res]) => (res.result.status === 'success' ? tr : Promise.reject(res)),
// submit the tr if the preflight is ok
submit,
safeSign(signWithChainweaver),
submitOne,
pollStatus,
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ITransactionDescriptor } from '@kadena/client';
import { createClient } from '@kadena/client';
import type { ChainId } from '@kadena/types';
import type { ChainId, ICommand, IUnsignedCommand } from '@kadena/types';

// you can edit this function if you want to use different network like dev-net or a private net
export const apiHostGenerator = ({
Expand Down Expand Up @@ -37,3 +38,7 @@ export const {
getStatus,
createSpv,
} = createClient(apiHostGenerator);

export const submitOne = async (
transaction: ICommand | IUnsignedCommand,
): Promise<ITransactionDescriptor> => submit(transaction as ICommand);
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any
type all = any;

// pipe async functions
export const asyncPipe =
(...args: Array<(arg: all) => all>): ((init: all) => Promise<all>) =>
(init: all): Promise<all> =>
args.reduce((chain, fn) => chain.then(fn), Promise.resolve(init));

export const head = (args: all[]): any => args[0];
import { isSignedTransaction } from '@kadena/client';
import type { ICommand, IUnsignedCommand } from '@kadena/types';

export const inspect =
(tag: string): (<T extends unknown>(data: T) => T) =>
<T extends any>(data: T): T => {
<T extends any>(tag: string) =>
(data: T): T => {
console.log(tag, data);
return data;
};

export const validateSign = (
tx: IUnsignedCommand,
signedTx: ICommand | IUnsignedCommand,
): ICommand => {
const { sigs, hash } = signedTx;
const txWithSigs = { ...tx, sigs };
if (txWithSigs.hash !== hash) {
throw new Error('Hash mismatch');
}
if (!isSignedTransaction(txWithSigs)) {
throw new Error('Signing failed');
}
return txWithSigs;
};

export const safeSign =
(
sign: (
transaction: IUnsignedCommand,
) => Promise<IUnsignedCommand | ICommand>,
) =>
async (tx: IUnsignedCommand) => {
if (tx.sigs.length === 0) return tx as ICommand;
const signedTx = await sign(tx);
return validateSign(tx, signedTx);
};
11 changes: 11 additions & 0 deletions packages/libs/client-utils/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This is a workaround for https://github.com/eslint/eslint/issues/3458
require('@rushstack/eslint-config/patch/modern-module-resolution');

module.exports = {
extends: ['@kadena-dev/eslint-config/profile/lib'],
parserOptions: { tsconfigRootDir: __dirname },
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@rushstack/typedef-var': 'off',
},
};
1 change: 1 addition & 0 deletions packages/libs/client-utils/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
contracts/*
6 changes: 6 additions & 0 deletions packages/libs/client-utils/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist
etc
lib
temp
**/*.md
tsdoc-metadata.json
82 changes: 82 additions & 0 deletions packages/libs/client-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!-- genericHeader start -->

# @kadena/client-utils

Utility functions build as a wrapper around @kadena/client

<picture>
<source srcset="https://raw.githubusercontent.com/kadena-community/kadena.js/main/common/images/Kadena.JS_logo-white.png" media="(prefers-color-scheme: dark)"/>
<img src="https://raw.githubusercontent.com/kadena-community/kadena.js/main/common/images/Kadena.JS_logo-black.png" width="200" alt="kadena.js logo" />
</picture>

<!-- genericHeader end -->

## Kadena client utils

Introducing `@kadena/client-utils`, a library that aims to provide a
higher-level API for interacting with smart contracts. This PR includes helpers
for the `coin` module, which can be imported using `@kadena/client-utils/coin`.
The library also exports utilities under `/core` for smart contract developers
to develop APIs, including some functions that can be used for any kind of smart
contracts.

- asyncPipe
- submitClient
- preflightClient
- dirtyReadClient
- crossChainClient

examples

```TS
import { getBalance, transferCrossChain } from "@kadena/client-utils/coin"
import { signWithChainweaver } from "@kadena/client"

const balance = await getBalance(
accountOne.account,
'fast-development',
'0',
'http://localhost:8080',
);

const result = await createAccount(
{
account: 'javad',
keyset: {
pred: 'keys-all',
keys: ['key-a', 'key-b'],
},
gasPayer: { account: 'gasPayer', publicKeys: [''] },
chainId: '0',
},
{
host: 'https://api.testnet.chainweb.com',
defaults: {
networkId: 'testnet04',
},
sign: signWithChainweaver,
},
)
// signed Tx
.on('sign', (data) => console.log(data))
// preflight result
.on('preflight', (data) => console.log(data))
// submit result
.on('submit', (data) => console.log(data))
// listen result
.on('listen', (data) => console.log(data))
.execute();
```

### Future work

- `npx create @kadena/client-utils`

- to allow community members to create their own interfaces for their
smart-contracts

- @kadena/client-utils/
- faucet
- marmalade
- principles
- namespace
Loading
Loading