Smart Contracts Reference
ULedger smart contracts are written in WebAssembly Text Format (.wat) and executed by the ULVM — ULedger's own WebAssembly virtual machine. Every deploy, upgrade, and invocation is a signed transaction on the blockchain.
Deploy Contract
Deploys a .wat smart contract to a blockchain. The request is multipart — the contract file is uploaded alongside the transaction parameters. The wallet must already be registered on the target blockchain.
Request
POST /api/v1/smartcontracts/deploy
Headers
X-AccessKey— Your entity access keyContent-Type: multipart/form-data
Form fields
walletAddress(required) — The wallet deploying the contractblockchainId(required) — Target blockchain IDfrom(required) — Sender address (usually same aswalletAddress)file(required) — The.watcontract filepayload— Optional deployment label or notepassphrase— Only if the wallet was created with one
Response
Returns the transaction result on success. The contract address is derived from the transaction ID — retrieve the block at the current height to find it.
- cURL
- TypeScript
curl -X POST \
'https://your-tms-url/api/v1/smartcontracts/deploy' \
-H 'X-AccessKey: your-entity-access-key' \
-F 'walletAddress=54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585' \
-F 'blockchainId=08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2' \
-F 'from=54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585' \
-F 'payload=my first contract' \
-F 'file=@./contract.wat'
import fs from 'fs';
import FormData from 'form-data';
const form = new FormData();
form.append('walletAddress', '54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585');
form.append('blockchainId', '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2');
form.append('from', '54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585');
form.append('payload', 'my first contract');
form.append('file', fs.createReadStream('./contract.wat'));
const res = await fetch('https://your-tms-url/api/v1/smartcontracts/deploy', {
method: 'POST',
headers: {
'X-AccessKey': 'your-entity-access-key',
...form.getHeaders(),
},
body: form,
});
const data = await res.json();
console.log(data);
Upgrade Contract
Upgrades an existing deployed contract with a new .wat file. The contract address stays the same — only the code changes. Previous versions are preserved on-chain.
Request
POST /api/v1/smartcontracts/upgrade
Headers
X-AccessKey— Your entity access keyContent-Type: multipart/form-data
Form fields
walletAddress(required) — The wallet performing the upgradeblockchainId(required) — Target blockchain IDcontractAddress(required) — Address of the contract to upgradefile(required) — The new.watcontract fileupgradeReason— A note describing what changedpassphrase— Only if the wallet was created with one
Response
Returns the upgrade transaction result on success.
- cURL
- TypeScript
curl -X POST \
'https://your-tms-url/api/v1/smartcontracts/upgrade' \
-H 'X-AccessKey: your-entity-access-key' \
-F 'walletAddress=54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585' \
-F 'blockchainId=08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2' \
-F 'contractAddress=your-contract-address' \
-F 'upgradeReason=fixed a bug in the main function' \
-F 'file=@./contract-v2.wat'
import fs from 'fs';
import FormData from 'form-data';
const form = new FormData();
form.append('walletAddress', '54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585');
form.append('blockchainId', '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2');
form.append('contractAddress', 'your-contract-address');
form.append('upgradeReason', 'fixed a bug in the main function');
form.append('file', fs.createReadStream('./contract-v2.wat'));
const res = await fetch('https://your-tms-url/api/v1/smartcontracts/upgrade', {
method: 'POST',
headers: {
'X-AccessKey': 'your-entity-access-key',
...form.getHeaders(),
},
body: form,
});
const data = await res.json();
console.log(data);
Invoke Contract
Calls a function on a deployed smart contract. Arguments are typed — the ULVM needs to know the type of each argument to encode it correctly before execution.
Request
POST /api/v1/smartcontracts/invoke/payload
Headers
X-AccessKey— Your entity access keyContent-Type: application/json
Body
walletAddress— The wallet signing the invocationblockchainId— Target blockchain IDcontractAddress(required) — The deployed contract addressfunctionName(required) — The exported function to callarguments— Array of typed arguments. Each entry has atypeandvalue. Supported types:int32,int64,float32,float64,bool,string,bytesgasLimit— Max gas for execution. Use0for no limit.passphrase— Only if the wallet was created with one
Response
Returns the invocation transaction result including any output from the contract function.
Example response
{
"transactionId": "a1b2c3...",
"status": "confirmed",
"output": "42",
"gasUsed": 100
}
- cURL
- TypeScript
curl -X POST \
'https://your-tms-url/api/v1/smartcontracts/invoke/payload' \
-H 'X-AccessKey: your-entity-access-key' \
-H 'Content-Type: application/json' \
-d '{
"walletAddress": "54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585",
"blockchainId": "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2",
"contractAddress": "your-contract-address",
"functionName": "main",
"arguments": [
{ "type": "string", "value": "hello" },
{ "type": "int32", "value": "42" }
],
"gasLimit": 0
}'
const res = await fetch('https://your-tms-url/api/v1/smartcontracts/invoke/payload', {
method: 'POST',
headers: {
'X-AccessKey': 'your-entity-access-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: '54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585',
blockchainId: '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2',
contractAddress: 'your-contract-address',
functionName: 'main',
arguments: [
{ type: 'string', value: 'hello' },
{ type: 'int32', value: '42' },
],
gasLimit: 0,
}),
});
const data = await res.json();
console.log('Output:', data.output);
Rollback Contract
Rolls back a deployed smart contract to a previously deployed version. All versions are preserved on-chain — this swaps the active bytecode back to the specified version number without losing history.
Request
POST /api/v1/smartcontracts/rollback
Headers
X-AccessKey— Your entity access keyContent-Type: application/json
Body
walletAddress(required) — The wallet that deployed the contractblockchainId(required) — Target blockchain IDcontractAddress(required) — The contract to roll backtargetVersion(required) — The version number to restore (e.g.1)passphrase(optional) — Only if the wallet was created with onerollbackReason(optional) — A note describing why you are rolling back
Response
Returns the rollback transaction result on success.
Example response
{
"transactionId": "rb1b2c3...",
"status": "confirmed",
"contractAddress": "your-contract-address",
"targetVersion": 1
}
- cURL
- TypeScript
curl -X POST \
'https://your-tms-url/api/v1/smartcontracts/rollback' \
-H 'X-AccessKey: your-entity-access-key' \
-H 'Content-Type: application/json' \
-d '{
"walletAddress": "54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585",
"blockchainId": "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2",
"contractAddress": "your-contract-address",
"targetVersion": 1,
"rollbackReason": "Reverting due to critical bug in V2"
}'
const res = await fetch('https://your-tms-url/api/v1/smartcontracts/rollback', {
method: 'POST',
headers: {
'X-AccessKey': 'your-entity-access-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: '54677be320b0bd704a99ee1f3d60c7309dfdee4810b1846d7b66ddbe0e84f585',
blockchainId: '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2',
contractAddress: 'your-contract-address',
targetVersion: 1,
rollbackReason: 'Reverting due to critical bug in V2',
}),
});
const data = await res.json();
console.log('Rollback tx:', data.transactionId);
Get Contract State
Retrieves the current key-value state stored by a smart contract. State is written by the contract's functions during invocation and persists between calls.
Request
GET /api/v1/smartcontracts/{blockchainId}/{contractAddress}/state
Headers
X-AccessKey— Your entity access key
Path parameters
blockchainId— The blockchain the contract is deployed oncontractAddress— The contract address
Response
Returns a map of all keys and values the contract has written to state storage.
Example response
{
"contract:version": "1",
"contract:owner": "54677be3...",
"counter": "42"
}
- cURL
- TypeScript
curl -X GET \
'https://your-tms-url/api/v1/smartcontracts/08c28f29.../your-contract-address/state' \
-H 'X-AccessKey: your-entity-access-key' \
-H 'Accept: application/json'
const blockchainId = '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2';
const contractAddress = 'your-contract-address';
const res = await fetch(
`https://your-tms-url/api/v1/smartcontracts/${blockchainId}/${contractAddress}/state`,
{
headers: {
'X-AccessKey': 'your-entity-access-key',
'Accept': 'application/json',
},
}
);
const state = await res.json();
console.log('Contract state:', state);
Get Contract Execution Trace
Returns the execution trace for a specific contract invocation. Useful for debugging — shows which WASM instructions executed, their gas cost, and any values read or written during the call.
Request
GET /api/v1/smartcontracts/{blockchainId}/{contractAddress}/trace/{txId}
Headers
X-AccessKey— Your entity access key
Path parameters
blockchainId— The blockchain the contract is deployed oncontractAddress— The contract addresstxId— The transaction ID of the invocation to trace
Response
Returns the full execution trace for the given invocation transaction.
Example response
{
"txId": "a1b2c3...",
"functionName": "getVersion",
"gasUsed": 120,
"output": "2",
"steps": [
{ "op": "i32.const", "value": 2 },
{ "op": "return" }
]
}
- cURL
- TypeScript
curl -X GET \
'https://your-tms-url/api/v1/smartcontracts/08c28f29.../your-contract-address/trace/a1b2c3...' \
-H 'X-AccessKey: your-entity-access-key' \
-H 'Accept: application/json'
const blockchainId = '08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2';
const contractAddress = 'your-contract-address';
const txId = 'a1b2c3d4e5f6...';
const res = await fetch(
`https://your-tms-url/api/v1/smartcontracts/${blockchainId}/${contractAddress}/trace/${txId}`,
{
headers: {
'X-AccessKey': 'your-entity-access-key',
'Accept': 'application/json',
},
}
);
const trace = await res.json();
console.log('Gas used:', trace.gasUsed);
console.log('Output:', trace.output);