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

[@kadena/client-utils] Implement Marmalade functions (Feat) #1484

Merged
merged 43 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
7713060
add marmalade generate contract script
nil-amrutlal Jan 16, 2024
3ecf4ef
create token and create token id functions
nil-amrutlal Jan 16, 2024
f2baef5
small refactor to create token id and create token
nil-amrutlal Jan 16, 2024
fc7b5e3
mint token functionality
nil-amrutlal Jan 16, 2024
2750216
transfer-create function
nil-amrutlal Jan 16, 2024
12a74f1
get balance function
nil-amrutlal Jan 16, 2024
8e0eba4
refactor createToken
nil-amrutlal Jan 16, 2024
8df7ac0
index file
nil-amrutlal Jan 17, 2024
76d5502
added unit testing for createId, create and mint tokens
nil-amrutlal Jan 19, 2024
3f98192
integration testing; lint and style fixes; index file for marmalade
nil-amrutlal Jan 22, 2024
873eb68
Merge commit '143f0429d14aec159691d3e78a838701af77552a' into feat/cli…
nil-amrutlal Jan 22, 2024
5c503e0
removed unecessary exports
nil-amrutlal Jan 22, 2024
a53cae6
omit sign in dirty reads
nil-amrutlal Jan 22, 2024
e09d96b
changeset file
nil-amrutlal Jan 22, 2024
f36ac58
Merge commit 'f253eec418d850d3719d7888beea603c36da894b' into feat/cli…
nil-amrutlal Feb 12, 2024
fc34898
Merge commit '351eda899e6629b139465d506d5573ba5924cacd' into feat/cli…
nil-amrutlal Feb 12, 2024
8bb2c25
marmalade integration testing init
nil-amrutlal Feb 14, 2024
86b0dd8
Merge commit 'd0a3df29886926cd9b2a28fd12622ecb4982f1f9' into feat/cli…
nil-amrutlal Feb 14, 2024
9539111
make chain argument declared at top;
nil-amrutlal Feb 14, 2024
b5a5cd5
ci changes: add apt-get update
nil-amrutlal Feb 14, 2024
8953ae3
default chain 0
nil-amrutlal Feb 14, 2024
a4b0de1
Merge commit '4a475f7f42316a16ae155a8547f8f1c3b53caea8' into feat/cli…
nil-amrutlal Feb 19, 2024
71c2cf7
unit testing to meet threshold
nil-amrutlal Feb 19, 2024
40344a4
Merge commit 'b05bbfe3cd603c197baa948703428bcb3e84a88e' into feat/cli…
nil-amrutlal Feb 19, 2024
3131b2a
Merge commit '88656854061acb28d9e9ef9f73ef1323967507ec' into feat/cli…
nil-amrutlal Feb 19, 2024
4a0a8e2
Merge commit '1465bdd81e447b188726b2e7416d8bc574950fc5' into feat/cli…
nil-amrutlal Feb 19, 2024
a94a97d
lint fixes
nil-amrutlal Feb 19, 2024
3a07197
Merge commit 'e65961e83b7a8c998baf10f8f830a96d71529a4c' into feat/cli…
nil-amrutlal Mar 12, 2024
72463b0
fix: minor fixes and comments resolutions
nil-amrutlal Mar 12, 2024
5bf95cb
Merge commit '4f810ef3d5763e4042f94f69dfc0d40c4f2df1a8' into feat/cli…
nil-amrutlal Apr 2, 2024
8fa5352
fix: adjusted precision type from number to Pact Int
nil-amrutlal Apr 3, 2024
cdd1af6
fix: lint fixes
nil-amrutlal Apr 3, 2024
e17bd57
Merge branch 'main' into feat/client-utils/marmalade-functions
wooglie May 2, 2024
5ad87a5
chore: update the create token capability signature
wooglie May 3, 2024
337468f
Merge branch 'main' into feat/client-utils/marmalade-functions
wooglie May 3, 2024
37b58d8
Merge branch 'main' into feat/client-utils/marmalade-functions
wooglie May 3, 2024
a0153c4
[@kadena/client-utils] Implement Marmalade functions - additions (#1945)
wooglie May 3, 2024
0307612
chore: add update-uri function
wooglie May 6, 2024
c187573
chore: format files
wooglie May 6, 2024
69866e0
Merge branch 'main' into feat/client-utils/marmalade-functions
wooglie May 9, 2024
1dc783d
Merge branch 'main' into feat/client-utils/marmalade-functions
wooglie May 13, 2024
b1d964f
[@kadena/client-utils] Implement Marmalade functions - Sale functions…
wooglie May 23, 2024
26ec4e3
chore: get quote function and reorganize imports (#2187)
wooglie May 27, 2024
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
5 changes: 5 additions & 0 deletions .changeset/sour-gorillas-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kadena/client-utils': patch
---

Added marmalade functions and correspondent integration testing
6 changes: 4 additions & 2 deletions packages/libs/client-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,11 @@
"lint:fmt": "prettier . --cache --check",
"lint:pkg": "lint-package",
"lint:src": "eslint src --ext .js,.ts",
"pactjs:generate:contract": "pactjs contract-generate --contract coin --api https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/0/pact",
"pactjs:generate:contract": "pactjs contract-generate --contract coin --contract marmalade-v2.ledger --contract marmalade-v2.collection-policy-v1 --contract marmalade-v2.policy-manager --contract marmalade-sale.conventional-auction --contract marmalade-sale.dutch-auction --api https://api.chainweb.com/chainweb/0.0/mainnet01/chain/8/pact",
"test": "vitest run",
"test:integration": "vitest run -c ./vitest.integration.config.ts",
"test:integration": "pnpm run test:integration:setup && vitest run -c ./vitest.integration.config.ts",
"test:integration:local": "vitest run -c ./vitest.integration.config.ts",
"test:integration:setup": "pnpm run build && ts-node src/scripts/setup-marmalade-test-env.ts",
"test:watch": "vitest"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,376 @@
import type { ChainId } from '@kadena/client';
import { createSignWithKeypair } from '@kadena/client';
import { PactNumber } from '@kadena/pactjs';
import type { IPactInt } from '@kadena/types';
import { describe, expect, it } from 'vitest';
import {
createCollection,
createCollectionId,
createToken,
createTokenId,
getCollection,
getCollectionToken,
getTokenBalance,
mintToken,
} from '../marmalade';
import type { ICreateTokenPolicyConfig } from '../marmalade/config';
import { NetworkIds } from './support/NetworkIds';
import { withStepFactory } from './support/helpers';
import { sourceAccount } from './test-data/accounts';

let tokenId: string | undefined;
let collectionId: string | undefined;
let collectionName: string | undefined;
const collectionSize: IPactInt = { int: '0' };
const chainId = '0' as ChainId;

const inputs = {
policyConfig: {
collection: true,
} as ICreateTokenPolicyConfig,
collection: {
collectionId,
},
chainId,
precision: { int: '0' },
uri: Math.random().toString(),
policies: ['marmalade-v2.collection-policy-v1'],
creator: {
account: sourceAccount.account,
keyset: {
keys: [sourceAccount.publicKey],
pred: 'keys-all' as const,
},
},
};
const config = {
host: 'http://127.0.0.1:8080',
defaults: {
networkId: 'development',
},
sign: createSignWithKeypair([sourceAccount]),
};

describe('createCollectionId', () => {
it('should return a collection id', async () => {
collectionName = `Test Collection #${Math.random().toString()}`;

collectionId = await createCollectionId({
collectionName,
chainId,
operator: {
keyset: {
keys: [sourceAccount.publicKey],
pred: 'keys-all' as const,
},
},
networkId: config.defaults.networkId,
host: config.host,
});

expect(collectionId).toBeDefined();
expect(collectionId).toMatch(/^collection:.{43}$/);

inputs.collection.collectionId = collectionId;
});
});

describe('createCollection', () => {
it('should create a collection', async () => {
const withStep = withStepFactory();

const result = await createCollection(
{
id: collectionId as string,
name: collectionName as string,
size: collectionSize,
operator: inputs.creator,
chainId,
},
config,
)
.on(
'sign',
withStep((step, tx) => {
expect(step).toBe(1);
expect(tx.sigs).toHaveLength(1);
expect(tx.sigs[0].sig).toBeTruthy();
}),
)
.on(
'preflight',
withStep((step, prResult) => {
expect(step).toBe(2);
if (prResult.result.status === 'failure') {
expect(prResult.result.status).toBe('success');
} else {
expect(prResult.result.data).toBe(true);
}
}),
)
.on(
'submit',
withStep((step, trDesc) => {
expect(step).toBe(3);
expect(trDesc.networkId).toBe(NetworkIds.development);
expect(trDesc.chainId).toBe(chainId);
expect(trDesc.requestKey).toBeTruthy();
}),
)
.on(
'listen',
withStep((step, sbResult) => {
expect(step).toBe(4);
if (sbResult.result.status === 'failure') {
expect(sbResult.result.status).toBe('success');
} else {
expect(sbResult.result.data).toBe(true);
}
}),
)
.execute();

expect(result).toBe(true);
});
});

describe('createTokenId', () => {
it('should return a token id', async () => {
tokenId = await createTokenId({
...inputs,
networkId: config.defaults.networkId,
host: config.host,
});

expect(tokenId).toBeDefined();
expect(tokenId).toMatch(/^t:.{43}$/);
});
});

describe('createToken', () => {
it('should create a token with policy', async () => {
const withStep = withStepFactory();

const tokenId = await createTokenId({
...inputs,
networkId: config.defaults.networkId,
host: config.host,
});

expect(tokenId).toBeDefined();
expect(tokenId).toMatch(/^t:.{43}$/);

const result = await createToken(
{
...inputs,
tokenId: tokenId as string,
},
config,
)
.on(
'sign',
withStep((step, tx) => {
expect(step).toBe(1);
expect(tx.sigs).toHaveLength(1);
expect(tx.sigs[0].sig).toBeTruthy();
}),
)
.on(
'preflight',
withStep((step, prResult) => {
expect(step).toBe(2);
if (prResult.result.status === 'failure') {
expect(prResult.result.status).toBe('success');
} else {
expect(prResult.result.data).toBe(true);
}
}),
)
.on(
'submit',
withStep((step, trDesc) => {
expect(step).toBe(3);
expect(trDesc.networkId).toBe(NetworkIds.development);
expect(trDesc.chainId).toBe(chainId);
expect(trDesc.requestKey).toBeTruthy();
}),
)
.on(
'listen',
withStep((step, sbResult) => {
expect(step).toBe(4);
if (sbResult.result.status === 'failure') {
expect(sbResult.result.status).toBe('success');
} else {
expect(sbResult.result.data).toBe(true);
}
}),
)
.execute();

expect(result).toBe(true);
});
});

describe('mintToken', () => {
it('should mint a token', async () => {
const withStep = withStepFactory();

const result = await mintToken(
{
...inputs,
tokenId: tokenId as string,
accountName: sourceAccount.account,
guard: {
account: sourceAccount.account,
keyset: {
keys: [sourceAccount.publicKey],
pred: 'keys-all' as const,
},
},
amount: new PactNumber(1).toPactDecimal(),
},
config,
)
.on(
'sign',
withStep((step, tx) => {
expect(step).toBe(1);
expect(tx.sigs).toHaveLength(1);
expect(tx.sigs[0].sig).toBeTruthy();
}),
)
.on(
'preflight',
withStep((step, prResult) => {
expect(step).toBe(2);
if (prResult.result.status === 'failure') {
expect(prResult.result.status).toBe('success');
} else {
expect(prResult.result.data).toBe(true);
}
}),
)
.on(
'submit',
withStep((step, trDesc) => {
expect(step).toBe(3);
expect(trDesc.networkId).toBe(NetworkIds.development);
expect(trDesc.chainId).toBe(chainId);
expect(trDesc.requestKey).toBeTruthy();
}),
)
.on(
'listen',
withStep((step, sbResult) => {
expect(step).toBe(4);
if (sbResult.result.status === 'failure') {
expect(sbResult.result.status).toBe('success');
} else {
expect(sbResult.result.data).toBe(true);
}
}),
)
.execute();

expect(result).toBe(true);

const balance = await getTokenBalance({
accountName: sourceAccount.account,
chainId,
tokenId: tokenId as string,
networkId: config.defaults.networkId,
host: config.host,
});

expect(balance).toBe(1);
});
it('should throw error when non-existent token is minted', async () => {
const nonExistingTokenId = 'non-existing-token';
const task = mintToken(
{
...inputs,
tokenId: nonExistingTokenId,
accountName: sourceAccount.account,
guard: {
account: sourceAccount.account,
keyset: {
keys: [sourceAccount.publicKey],
pred: 'keys-all' as const,
},
},
amount: new PactNumber(1).toPactDecimal(),
},
config,
);

await expect(() => task.execute()).rejects.toThrowError(
new Error('with-read: row not found: non-existing-token'),
);
});
});

describe('getCollection', () => {
it('should get the collection details', async () => {
const result = await getCollection({
chainId,
collectionId: collectionId as string,
networkId: config.defaults.networkId,
host: config.host,
});

expect(result).toStrictEqual({
id: collectionId,
'max-size': {
int: Number(collectionSize.int),
},
name: collectionName,
'operator-guard': inputs.creator.keyset,
size: {
int: 1,
},
});
});
it('should throw an error if token does not exist', async () => {
const nonExistingTokenId = 'non-existing-collection';
const task = getCollection({
collectionId: nonExistingTokenId,
chainId,
networkId: config.defaults.networkId,
host: config.host,
});

await expect(() => Promise.resolve(task)).rejects.toThrowError(
new Error(`read: row not found: non-existing-collection`),
);
});
});

describe('getCollectionToken', () => {
it('should get the collection token details', async () => {
const result = await getCollectionToken({
chainId,
tokenId: tokenId as string,
networkId: config.defaults.networkId,
host: config.host,
});

expect(result).toStrictEqual({
id: tokenId,
'collection-id': collectionId,
});
});
it('should throw an error if token does not exist', async () => {
const nonExistingTokenId = 'non-existing-token';
const task = getCollectionToken({
chainId,
tokenId: nonExistingTokenId,
networkId: config.defaults.networkId,
host: config.host,
});

await expect(() => Promise.resolve(task)).rejects.toThrowError(
new Error(`read: row not found: non-existing-token`),
);
});
});
Loading