Upgrading from @kadena/client 0.x to 1.0.0
The highlights of the difference between 0.x and 1.0.0 are:
- the expression generation is separate from transaction building. This allows for multiple statements per transaction
- the client is it's own separate entity
- signing is applied on a vanilla JS Object
Here are two examples of old to new rewrites
Sending a transaction 'transfer'
Old implementation
async function transaction(
sender: string,
senderPublicKey: string,
receiver: string,
amount: IPactDecimal,
): Promise<void> {
const unsignedTransaction = Pact.modules.coin
.transfer(sender, receiver, amount)
.addCap('coin.GAS', senderPublicKey)
.addCap('coin.TRANSFER', senderPublicKey, sender, receiver, amount)
.setMeta({ sender }, 'testnet04');
const res = await signWithChainweaver(unsignedTransaction);
const sendRequests = res.map((tx) => {
console.log('sending transaction', tx.code);
return tx.send(testnetChain1ApiHost);
});
const sendResponses = await Promise.all(sendRequests);
sendResponses.map(async function (sendResponse: SendResponse): Promise<void> {
const requestKey = (await sendRequests[0]).requestKeys[0];
await pollMain(requestKey);
console.log(`Transaction '${requestKey}' finished`);
});
}
async function pollMain(...requestKeys: string[]): Promise<void> {
// ... some code to poll the status of the requestKeys
}
async function transaction(
sender: string,
senderPublicKey: string,
receiver: string,
amount: IPactDecimal,
): Promise<void> {
const unsignedTransaction = Pact.modules.coin
.transfer(sender, receiver, amount)
.addCap('coin.GAS', senderPublicKey)
.addCap('coin.TRANSFER', senderPublicKey, sender, receiver, amount)
.setMeta({ sender }, 'testnet04');
const res = await signWithChainweaver(unsignedTransaction);
const sendRequests = res.map((tx) => {
console.log('sending transaction', tx.code);
return tx.send(testnetChain1ApiHost);
});
const sendResponses = await Promise.all(sendRequests);
sendResponses.map(async function (sendResponse: SendResponse): Promise<void> {
const requestKey = (await sendRequests[0]).requestKeys[0];
await pollMain(requestKey);
console.log(`Transaction '${requestKey}' finished`);
});
}
async function pollMain(...requestKeys: string[]): Promise<void> {
// ... some code to poll the status of the requestKeys
}
New implementation
const NETWORK_ID: string = 'testnet04';
async function transfer(
sender: string,
senderPublicKey: string,
receiver: string,
amount: IPactDecimal,
): Promise<void> {
const transaction = Pact.builder
.execution(
// pact expression
Pact.modules.coin.transfer(sender, receiver, amount),
)
// add signers
.addSigner(senderPublicKey, (withCapability) => [
// add capabilities
withCapability('coin.GAS'),
withCapability('coin.TRANSFER', sender, receiver, amount),
])
// set chainId and sender
.setMeta({ chainId: '0', sender })
.setNetworkId(NETWORK_ID)
// will create a IUnsignedTransaction { cmd, hash, sigs }
.createTransaction();
const signedTx = await signWithChainweaver(transaction);
// create generic client
const client = createClient(apiHostGenerator);
// check if all necessary signatures are added
if (isSignedTransaction(signedTx)) {
const transactionDescriptor = await client.submit(signedTx);
const response = await client.listen(transactionDescriptor, {});
if (response.result.status === 'failure') {
throw response.result.error;
} else {
console.log(response.result);
}
}
}
transfer(senderAccount, senderPublicKey, receiverAccount, {
decimal: '13.37',
}).catch(console.error);
const NETWORK_ID: string = 'testnet04';
async function transfer(
sender: string,
senderPublicKey: string,
receiver: string,
amount: IPactDecimal,
): Promise<void> {
const transaction = Pact.builder
.execution(
// pact expression
Pact.modules.coin.transfer(sender, receiver, amount),
)
// add signers
.addSigner(senderPublicKey, (withCapability) => [
// add capabilities
withCapability('coin.GAS'),
withCapability('coin.TRANSFER', sender, receiver, amount),
])
// set chainId and sender
.setMeta({ chainId: '0', sender })
.setNetworkId(NETWORK_ID)
// will create a IUnsignedTransaction { cmd, hash, sigs }
.createTransaction();
const signedTx = await signWithChainweaver(transaction);
// create generic client
const client = createClient(apiHostGenerator);
// check if all necessary signatures are added
if (isSignedTransaction(signedTx)) {
const transactionDescriptor = await client.submit(signedTx);
const response = await client.listen(transactionDescriptor, {});
if (response.result.status === 'failure') {
throw response.result.error;
} else {
console.log(response.result);
}
}
}
transfer(senderAccount, senderPublicKey, receiverAccount, {
decimal: '13.37',
}).catch(console.error);
Read from the blockchain 'getBalance'
Old implementation
async function getBalance(account: string): Promise<void> {
// generation of transaction and expression as one, and the client is part of the transaction
const res = await Pact.modules.coin['get-balance'](account).local(
'http://host.com/chain/0/pact',
);
console.log(res);
}
const myAccount: string =
'k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94';
getBalance(myAccount).catch(console.error);
async function getBalance(account: string): Promise<void> {
// generation of transaction and expression as one, and the client is part of the transaction
const res = await Pact.modules.coin['get-balance'](account).local(
'http://host.com/chain/0/pact',
);
console.log(res);
}
const myAccount: string =
'k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94';
getBalance(myAccount).catch(console.error);
New implementation:
async function getBalance(account: string): Promise<void> {
// `Pact.builder.execution` accepts a number of `Pact.modules.<module>.<fun>` calls
const transaction = Pact.builder
.execution(Pact.modules.coin['get-balance'](account))
.setMeta({ chainId: '1' })
.createTransaction();
// client creation is separate from the transaction builder
const staticClient = createClient('http://host.com/chain/0/pact');
const genericClient = createClient(
({ networkId, chainId }) =>
`http://${networkId}.host.com/chain/${chainId}/pact`,
);
const res = await staticClient.local(transaction, {
preflight: false,
signatureVerification: false,
});
console.log(res);
}
getBalance(account).catch(console.error);
async function getBalance(account: string): Promise<void> {
// `Pact.builder.execution` accepts a number of `Pact.modules.<module>.<fun>` calls
const transaction = Pact.builder
.execution(Pact.modules.coin['get-balance'](account))
.setMeta({ chainId: '1' })
.createTransaction();
// client creation is separate from the transaction builder
const staticClient = createClient('http://host.com/chain/0/pact');
const genericClient = createClient(
({ networkId, chainId }) =>
`http://${networkId}.host.com/chain/${chainId}/pact`,
);
const res = await staticClient.local(transaction, {
preflight: false,
signatureVerification: false,
});
console.log(res);
}
getBalance(account).catch(console.error);