Skip to content

Smart Contract Tools overview

This article introduces tools designed to help developers working with smart contracts on the blockchain. These tools offer a range of capabilities, from testing smart contracts to facilitating command-line interactions with the blockchain, and even integrating the blockchain with your own applications.

Partisia Platform browser

Partisia platform browser is a web-based interface which translates the private blockchains data into a user-friendly application. Partisia Platform browser is essentially a complete UI for a private deployment.

Partisia Platform browser can be used to:

  • Display details for the entire ledger: blocks and transactions.
  • Interact with any smart contract.
  • Deploy your own new smart contracts.
  • Create local references of contracts and accounts to help you keep track of already deployed contracts.

Command-line tools

cargo pbc is an umbrella for multiple sub-tools. The tools assist you in interacting with the blockchain and working with smart contracts. These tools are thoroughly documented when using them within cargo pbc, enabling you to explore their capabilities inside cargo pbc. Below are a short description and use case for each of these sub-tools.

Pre requisite to use any cargo pbc commands

If you want to use any of the command-line tools or below commands you need to install the smart contract compiler "cargo pbc".

The Compiler build

This is a primary part of developings smart contracts. The build command compiles rust smart contracts and ZK Rust smart contracts. It compiles and returns .abi file and a .wasm for rust contracts or .zkwa for ZK rust contracts.

Blockchain interaction

To interact with the blockchain you can use the command line tool: cargo pbc. There are 3 main commands:

  • transaction
  • account
  • contract

It can help you specifically with:

  • Sending transactions to smart contracts
  • Deploying your own smart contracts
  • Showing smart contracts state
  • Sending secret inputs and viewing secret variables

The ABI tool abi

This tool is focused on helping you understand the ABI, actions and state of a contract. By using the command cargo pbc abi show, you can view information about a compiled contract's state type, initialization, actions, and variables. It simplifies the process of identifying shortnames for existing contracts using optional arguments. This tool is using the abi-client.

Example command:

cargo pbc abi show example-contracts/target/wasm32-unknown-unknown/release/auction_contract.abi
Response from example command
pub struct Bid {
bidder: Address,
amount: u128,
}
pub struct SecretVarId {
raw_id: u32,
}
pub struct TokenClaim {
tokens_for_bidding: u128,
tokens_for_sale: u128,
}
#[state]
pub struct AuctionContractState {
contract_owner: Address,
start_time_millis: i64,
end_time_millis: i64,
token_amount_for_sale: u128,
token_for_sale: Address,
token_for_bidding: Address,
highest_bidder: Bid,
reserve_price: u128,
min_increment: u128,
claim_map: Map<Address, TokenClaim>,
status: u8,
}
#[init]
pub fn initialize (
token_amount_for_sale: u128,
token_for_sale: Address,
token_for_bidding: Address,
reserve_price: u128,
min_increment: u128,
auction_duration_hours: u32,
)
#[action(shortname = 0x01)]
pub fn start ()
#[action(shortname = 0x03)]
pub fn bid (
bid_amount: u128,
)
#[action(shortname = 0x05)]
pub fn claim ()
#[action(shortname = 0x06)]
pub fn execute ()
#[action(shortname = 0x07)]
pub fn cancel ()
#[callback(shortname = 0x02)]
pub fn start_callback ()
#[callback(shortname = 0x04)]
pub fn bid_callback (
bid: Bid,
)

The ABI codegen tool abi codegen

Codegen produces autogenerated code in both Java & TypeScript to streamline interactions with contract actions and deserializing contracts states. The autogenerated code provides methods to interact with actions based on a smart contracts abi. If you are working with Java, we recommend you follow the readme here to automate your usage of abi codegen.

Abi codegen can also be used manually. Here is an example of how:

cargo pbc abi codegen --ts mySmartContract/target/wasm32-unknown-unknown/release/auction_contract.abi mySmartContract/AutogeneratedCode/auction_contract.ts
Response from example command
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import BN from "bn.js";
import {
AbiParser,
AbstractBuilder, BigEndianReader,
FileAbi, FnKinds, FnRpcBuilder, RpcReader,
ScValue,
ScValueEnum, ScValueOption,
ScValueStruct,
StateReader, TypeIndex,
BlockchainAddress,
Hash,
BlockchainPublicKey,
Signature,
BlsPublicKey,
BlsSignature
} from "@privacyblockchain/ts-abi";
import {BigEndianByteOutput} from "@secata-public/bitmanipulation-ts";

const fileAbi: FileAbi = new AbiParser(Buffer.from(
"50424341424909040005020000000004010000000342696400000002000000066269646465720d00000006616d6f756e7405010000000a546f6b656e436c61696d0000000200000012746f6b656e735f666f725f62696464696e67050000000f746f6b656e735f666f725f73616c6505010000001441756374696f6e436f6e747261637453746174650000000b0000000e636f6e74726163745f6f776e65720d0000001173746172745f74696d655f6d696c6c6973090000000f656e645f74696d655f6d696c6c69730900000015746f6b656e5f616d6f756e745f666f725f73616c65050000000e746f6b656e5f666f725f73616c650d00000011746f6b656e5f666f725f62696464696e670d0000000e686967686573745f62696464657200000000000d726573657276655f7072696365050000000d6d696e5f696e6372656d656e740500000009636c61696d5f6d61700f0d00010000000673746174757301010000000b536563726574566172496400000001000000067261775f69640300000008010000000a696e697469616c697a65ffffffff0f0000000600000015746f6b656e5f616d6f756e745f666f725f73616c65050000000e746f6b656e5f666f725f73616c650d00000011746f6b656e5f666f725f62696464696e670d0000000d726573657276655f7072696365050000000d6d696e5f696e6372656d656e74050000001661756374696f6e5f6475726174696f6e5f686f75727303020000000573746172740100000000030000000e73746172745f63616c6c6261636b0200000000020000000362696403000000010000000a6269645f616d6f756e7405030000000c6269645f63616c6c6261636b04000000010000000362696400000200000005636c61696d05000000000200000007657865637574650600000000020000000663616e63656c07000000000002",
"hex"
)).parseAbi();

type Option<K> = K | undefined;

export interface Bid {
bidder: BlockchainAddress;
amount: BN;
}

export function newBid(bidder: BlockchainAddress, amount: BN): Bid {
return {bidder, amount}
}

function fromScValueBid(structValue: ScValueStruct): Bid {
return {
bidder: BlockchainAddress.fromBuffer(structValue.getFieldValue("bidder")!.addressValue().value),
amount: structValue.getFieldValue("amount")!.asBN(),
};
}

function buildRpcBid(value: Bid, builder: AbstractBuilder) {
const structBuilder = builder.addStruct();
structBuilder.addAddress(value.bidder.asBuffer());
structBuilder.addU128(value.amount);
}

export interface TokenClaim {
tokensForBidding: BN;
tokensForSale: BN;
}

export function newTokenClaim(tokensForBidding: BN, tokensForSale: BN): TokenClaim {
return {tokensForBidding, tokensForSale}
}

function fromScValueTokenClaim(structValue: ScValueStruct): TokenClaim {
return {
tokensForBidding: structValue.getFieldValue("tokens_for_bidding")!.asBN(),
tokensForSale: structValue.getFieldValue("tokens_for_sale")!.asBN(),
};
}

export interface AuctionContractState {
contractOwner: BlockchainAddress;
startTimeMillis: BN;
endTimeMillis: BN;
tokenAmountForSale: BN;
tokenForSale: BlockchainAddress;
tokenForBidding: BlockchainAddress;
highestBidder: Bid;
reservePrice: BN;
minIncrement: BN;
claimMap: Map<BlockchainAddress, TokenClaim>;
status: number;
}

export function newAuctionContractState(contractOwner: BlockchainAddress, startTimeMillis: BN, endTimeMillis: BN, tokenAmountForSale: BN, tokenForSale: BlockchainAddress, tokenForBidding: BlockchainAddress, highestBidder: Bid, reservePrice: BN, minIncrement: BN, claimMap: Map<BlockchainAddress, TokenClaim>, status: number): AuctionContractState {
return {contractOwner, startTimeMillis, endTimeMillis, tokenAmountForSale, tokenForSale, tokenForBidding, highestBidder, reservePrice, minIncrement, claimMap, status}
}

function fromScValueAuctionContractState(structValue: ScValueStruct): AuctionContractState {
return {
contractOwner: BlockchainAddress.fromBuffer(structValue.getFieldValue("contract_owner")!.addressValue().value),
startTimeMillis: structValue.getFieldValue("start_time_millis")!.asBN(),
endTimeMillis: structValue.getFieldValue("end_time_millis")!.asBN(),
tokenAmountForSale: structValue.getFieldValue("token_amount_for_sale")!.asBN(),
tokenForSale: BlockchainAddress.fromBuffer(structValue.getFieldValue("token_for_sale")!.addressValue().value),
tokenForBidding: BlockchainAddress.fromBuffer(structValue.getFieldValue("token_for_bidding")!.addressValue().value),
highestBidder: fromScValueBid(structValue.getFieldValue("highest_bidder")!.structValue()),
reservePrice: structValue.getFieldValue("reserve_price")!.asBN(),
minIncrement: structValue.getFieldValue("min_increment")!.asBN(),
claimMap: new Map([...structValue.getFieldValue("claim_map")!.mapValue().map].map(([k1, v2]) => [BlockchainAddress.fromBuffer(k1.addressValue().value), fromScValueTokenClaim(v2.structValue())])),
status: structValue.getFieldValue("status")!.asNumber(),
};
}

export function deserializeAuctionContractState(bytes: Buffer): AuctionContractState {
const scValue = new StateReader(bytes, fileAbi.contract).readState();
return fromScValueAuctionContractState(scValue);
}

export interface SecretVarId {
rawId: number;
}

export function newSecretVarId(rawId: number): SecretVarId {
return {rawId}
}

function fromScValueSecretVarId(structValue: ScValueStruct): SecretVarId {
return {
rawId: structValue.getFieldValue("raw_id")!.asNumber(),
};
}

export function initialize(tokenAmountForSale: BN, tokenForSale: BlockchainAddress, tokenForBidding: BlockchainAddress, reservePrice: BN, minIncrement: BN, auctionDurationHours: number): Buffer {
const fnBuilder = new FnRpcBuilder("initialize", fileAbi.contract);
fnBuilder.addU128(tokenAmountForSale);
fnBuilder.addAddress(tokenForSale.asBuffer());
fnBuilder.addAddress(tokenForBidding.asBuffer());
fnBuilder.addU128(reservePrice);
fnBuilder.addU128(minIncrement);
fnBuilder.addU32(auctionDurationHours);
return fnBuilder.getBytes();
}

export function start(): Buffer {
const fnBuilder = new FnRpcBuilder("start", fileAbi.contract);
return fnBuilder.getBytes();
}

export function bid(bidAmount: BN): Buffer {
const fnBuilder = new FnRpcBuilder("bid", fileAbi.contract);
fnBuilder.addU128(bidAmount);
return fnBuilder.getBytes();
}

export function claim(): Buffer {
const fnBuilder = new FnRpcBuilder("claim", fileAbi.contract);
return fnBuilder.getBytes();
}

export function execute(): Buffer {
const fnBuilder = new FnRpcBuilder("execute", fileAbi.contract);
return fnBuilder.getBytes();
}

export function cancel(): Buffer {
const fnBuilder = new FnRpcBuilder("cancel", fileAbi.contract);
return fnBuilder.getBytes();
}

Libraries

Partisia Platform offers a set of different libraries to help you interact with smart contracts and work with the states of smart contracts on the chain.

client

Facilitates communication with a blockchain node. It helps you to interact with the blockchain programmatically. It can get data about blocks, transactions, smart contracts, accounts etc. It has the functionality to create and send transactions.

abi-client

Our Smart Contract Binary Interface Client Library. It offers a standard binary interface for deploying contracts and creating transactions, making it ideal for several use cases:

  • Creating binary RPC, which calls an action with parameters on a smart contract.
  • Decode binary contract states to readable types.
  • Decode binary parts of transactions and events.

ABI-Client is available in the following programming languages:

When using the abi-client using codegen can help you as a developer to create a plug-and-play interactions with the blockchain. Abi-client can be used to read from contracts that is not necessarily linked to a specific contract on the blockchain. The strength of codegen compared to abi-client is to handle specific contracts you want to work with. Whereas abi-client is more generalistic in its approach to contracts not already know to the system.
We have created an example client to showcase how to work with the abi-client.

zk-client

Sending secret input to ZK Rust smart contracts. The zk-client is a library that can help you interact with the blockchain. Secondly the zk-client can fetch the secret data that you have ownership of from a ZK contract deployed onto the chain. You can visit the tests inside the projects to see how it works and start from there.

zk-client is available in the following programming languages:

Example client

This is a front end and a backend example of how to integrate you application with Partisia Blockchain, specifically it uses the client and the abi-client to send transactions and read states of the contracts.

Example client is available in the following programming languages:

Partisia All Rights Reserved © 2023