Invoke a Smart Contract (TypeScript)
This tutorial shows the core logic to invoke a ULVM smart contract function using the ULedger TypeScript SDK (WASM-backed).
We’ll use the same example contract from ULVM Smart Contract Basics:
testStoreAndRetrieve(value: i32) -> i32testStoreAndRetrieveArray() -> i32
✅ Goal: submit an
INVOKE_SMART_CONTRACTtransaction where:
contractAddress= the deployed contract addressfunctionName= exported function nameargs=Array<string | Uint8Array>gasLimit= optional number
In the TypeScript SDK, you typically invoke via:
session.invokeContract({ blockchainId, contractAddress, functionName, args, gasLimit })rather than manually building
ULTransactionInput.
1) What you need before invoking
You need:
- A wallet that can submit transactions on your chain.
- A deployed contract address (the same
contractAddressyou used during deploy). - Node endpoint and blockchainId.
On many chains, your wallet must be registered on-chain before it can submit contract calls.
If you see REJECTED_BY_UNAUTHORIZED, register first:
await session.registerWallet(blockchainId);
2) Create a wallet (example)
This tutorial focuses on invocation logic, so we’ll keep wallet creation minimal. (You can also restore from JSON you previously saved.)
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Generate a wallet (for production, you’ll likely persist/restore it instead)
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });
console.log("Wallet address:", wallet.address);
3) Create a transaction session
Use the SDK helper to create an initialized session.
const nodeEndpoint = "https://tn-w-1.uledger.net/";
const blockchainId = "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2";
const session = await sdk.createSession(nodeEndpoint, wallet);
4) Invoke the contract
Example A — call testStoreAndRetrieveArray() (no args)
const contractAddress = "<YOUR_CONTRACT_ADDRESS>";
const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieveArray",
args: [], // optional; empty is fine
gasLimit: 100000, // optional
});
console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
Example B — call testStoreAndRetrieve(value: i32) (one arg)
The TypeScript SDK accepts args as string or Uint8Array.
If your contract expects a raw i32, you can encode a 32-bit integer into 4 bytes (little-endian is a common convention):
function i32LE(n: number): Uint8Array {
const buf = new ArrayBuffer(4);
new DataView(buf).setInt32(0, n, true);
return new Uint8Array(buf);
}
const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieve",
args: [i32LE(123)],
gasLimit: 100000,
});
console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
If your ULVM runtime requires a specific serializer (like Go’s
transaction.Encode(...)), use the TypeScript SDK equivalent if it exists in your build. Based on thetransaction.d.tsyou shared, anEncode(...)helper is not currently exposed from the TS surface, so this guide uses a simple byte encoding example.
5) Full minimal example (core logic)
This example invokes testStoreAndRetrieve(123).
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
function i32LE(n: number): Uint8Array {
const buf = new ArrayBuffer(4);
new DataView(buf).setInt32(0, n, true);
return new Uint8Array(buf);
}
async function main() {
const sdk = await getULedgerSDK();
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });
const nodeEndpoint = "https://tn-w-1.uledger.net/";
const blockchainId = "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2";
const session = await sdk.createSession(nodeEndpoint, wallet);
// If you get REJECTED_BY_UNAUTHORIZED, uncomment:
// await session.registerWallet(blockchainId);
const contractAddress = "<YOUR_CONTRACT_ADDRESS>";
const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieve",
args: [i32LE(123)],
gasLimit: 100000,
});
console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
}
main().catch((e) => {
console.error("Invoke failed:", e);
process.exit(1);
});
Notes and common gotchas
Function name must match exactly
functionName must match the exported ULVM function name:
export function testStoreAndRetrieve(value: i32): i32 { ... }
So in TypeScript:
functionName: "testStoreAndRetrieve"
Contract address
In the TypeScript SDK, invokeContract() takes contractAddress directly.
Use the same contract address you deployed to (the value you passed as contractAddress during deploy).
Gas limit
If you’re unsure, start around 100000 for basic examples and adjust later.
Next steps
- Move on to: **ERC-20 Tokens with the Go SDK (TS)