Skip to main content

Call contract functions

Every interaction with the blockchain involves the same basic steps:

  • Connecting to an appropriate network endpoint for the development, test, or main network that you want to interact with.
  • Providing a payload with your request that's properly formatted and contains all of the information required to complete any particular task.
  • Signing the transaction with a valid key that has whatever permissions a specific task might require.

There's little difference between interacting with the blockchain directly through the API or through an abstraction layer such as the Kadena CLI or Kadena.js libraries. The difference is primarily a matter of preference about how you want to deliver the request. However, when you are calling functions, you might want to consider whether you want to make a local request or send the request to the blockchain.

In many cases, sending the request to the /local endpoint has advantages over sending the request to the network using the /send endpoint. This guide provides examples for calling functions using both endpoints and using curl, the Kadena CLI, and the Kadena.js client libraries.

Using a YAML request and curl

If you want to call a function that modifies informatipon stored in the blockchain, you should make the transaction request using the /send endpoint. If you want to call a function that reads information from the blockchain, you should make the transaction request using the /local endpoint. For example, the free.vote-topics contract has three functions: init, vote, and getVotes. The init and vote functions modify the votes table, so they should be called using the /send endpoint. The getVotes function reads information from the table, so it can be called using the /local endpoint.

To call the init function using a curl command and /send endpoint:

  1. Generate a random public and secret key pair and save them to a file.

    pact --genkey > pistolas.yaml
  2. Construct the transaction using the YAML transaction request format for an unsigned transaction.

    code: |-
    (free.simple-vote.init)
    data:
    ks: {
    keys: ["3bdb1d3c48a1bb5f072b067e265ce5d9a5eabf5e290128be4d2623dd559ca698"],
    pred: "keys-all"
    }
    publicMeta:
    chainId: "3"
    sender: "pact-generated-key"
    gasLimit: 63000
    gasPrice: 0.00000001
    ttl: 900
    signers:
    - public: 3bdb1d3c48a1bb5f072b067e265ce5d9a5eabf5e290128be4d2623dd559ca698
    caps: []
    networkId: "development"
    type: exec
  3. Prepare the YAML transaction request to be signed.

    pact --unsigned call-init-signers.yaml > tx-init.yaml
  4. Add a signature from your randomly-generated key pair and convert the request to a valid JSON object.

    cat tx-init.yaml | pact add-sig pistolas.yaml > tx-signed-init.json
  5. Use curl to connect to the /send endpoint on the development, testnet04 or mainnet01 network.

    curl -X POST -H "Content-Type: application/json" -d "@tx-signed-init.json" http://localhost:8080/chainweb/0.0/development/chain/3/pact/api/v1/send

To call the getVotes function using a curl command and /local endpoint:

  1. Construct the transaction using the YAML transaction request format for an unsigned transaction.

    code: |-
    (free.simple-vote.getVotes "A")
    data:
    publicMeta:
    chainId: "3"
    sender: "pact-generated-key"
    gasLimit: 63000
    gasPrice: 0.00000001
    ttl: 900
    networkId: "development"
    type: exec
  2. Format the request and use curl to connect to the /local endpoint on the development, testnet04 or mainnet01 network.

    pact --apireq simple-call.yaml --local | curl -X POST -H "Content-Type: application/json" \
    --json @- http://localhost:8080/chainweb/0.0/development/chain/3/pact/api/v1/local

    The command returns the result from the /local endpoint. In this example, five votes have been recorded for topic "A".

    {"gas":18,"result":{"status":"success","data":5},"reqKey":"tg201pWYbHUdh3umkbKEeKyvRjWycBQlZSDcrCwasts",...}

Using kadena-cli commands

With the kadena-cli, you can construct a transaction template to call functions in smart contracts. You can then customize the transactions to call the same function on different chains or different networks. Depending on how you create your template, you can also use it to call different types of functions with interactive prompting for values or by setting command-line options.

To call a smart contract function using kadena-cli:

  1. Create a call-function.ktpl template file with the template variables for calling a function.

    call-function.yaml - YAML configuration for executing a smart contract function
    code: |-
    {{namespace.module.function args}}
    data:
    publicMeta:
    chainId: "{{chain-id}}"
    sender: "{{{account-name}}}"
    gasLimit: 80300
    gasPrice: 0.000001
    ttl: 600
    networkId: "{{network-id}}"
    signers:
    - public: "{{public-key}}"
    caps: []
    type: exec

    For convenience, you can move the deploy-contract.ktpl template to the .kadena/transaction-templates directory, so that the template is listed when you add transactions with interactive prompting.

  2. Create a new unsigned transaction using the kadena tx add command and the call-function.ktpl template and follow the prompts displayed to set the appropriate information.

    For example, the prompts and output for calling the vote function look similar to the following:

    ? Which template do you want to use: call-function.ktpl
    ? File path of data to use for template .json or .yaml (optional):
    ? Template value namespace.module.function args: (free.vote-topics.vote "B")
    ? Template value chain-id: 3
    ? Template value account-name: k:58705e8699678bd15bbda2cf40fa236694895db614aafc82cf1c06c014ca963c
    ? Template value network-id: development
    ? Template value public-key: 58705e8699678bd15bbda2cf40fa236694895db614aafc82cf1c06c014ca963c
    ? Where do you want to save the output: test-vote-2
  3. Sign the unsigned transaction using the kadena tx sign command and the transaction file name generated by the kadena tx add command.

  4. Send the signed transaction using the kadena tx send command and the signed transaction file name generated by the kadena tx sign command.

You can use the same template to call the getVotes function and use kadena tx test to test the function call results.

kadena tx add
kadena tx sign
kadena tx test

Using the Kadena client library

If you're familiar with JavaScript or TypeScript, you can use the @kadena/client library to write scripts for common tasks. The @kadena/client library implements a TypeScript-based API for interacting with smart contracts and Chainweb nodes. The library provides functions that simplify building transactions with Pact commands and connecting to blockchain nodes.

You should note that creating the client connection is separate from using the Pact.builder function to construct transactions. This example calls the greet function defined in the simplemodule that's been deployed in the free namespace on the testnet04 network.

import { Pact, createClient } from '@kadena/client';

const client = createClient();

const command = async (functionName: string) => {
const unsignedTransaction = Pact.builder
.execution(functionName)
.setMeta({
chainId: '1',
gasLimit: 2500,
})
.setNetworkId('testnet04')
.createTransaction();

try {
const res = await client.dirtyRead(unsignedTransaction);
if (res.result.status === 'success') {
console.log(res.result.data);
return res.result.data;
} else {
console.log('No data returned:', res);
}
} catch (error) {
console.error('Error with dirtyRead or data processing:', error);
}

try {
const res = await client.dirtyRead(unsignedTransaction);
if (res.result.status === 'success') {
console.log(res.result.data);
return res.result.data;
} else {
console.log('No data returned:', res);
}
} catch (error) {
console.error('Error with dirtyRead or data processing:', error);
}
};

command('(free.simplemodule.greet)').catch(console.error);