This guide walks you through deploying smart contracts using Oumla’s contract template system.
Two Ways to Use Oumla: This guide uses the TypeScript SDK. You can also accomplish the same tasks using direct REST API calls - see the API Reference for endpoint details.
Overview
The contract deployment workflow involves:
- Create or Select Template - Use an existing template or create a new one
- Get Constructor Info - Understand required constructor parameters
- Deploy Contract - Deploy with your parameters
- Check Status - Monitor the async deployment workflow
- Interact with Contract - Call functions on the deployed contract
Contract deployment uses Temporal workflows for async processing. You’ll need to check workflow status to know when deployment completes.
Prerequisites
Before starting, ensure you have:
- An initialized SDK client
- A profile created
- An address generated (for contract deployment)
- Your client share (for signing operations)
Step 1: Get Available Templates
List available contract templates:
import { OumlaSdkApiClient, OumlaSdkApiEnvironment } from '@oumla/sdk';
const client = new OumlaSdkApiClient({
environment: OumlaSdkApiEnvironment.Sandbox,
apiKey: 'your-api-key-here'
});
// Get all templates
const templates = await client.contractTemplates.getContracts({
skip: 0,
take: 25
});
console.log('Available templates:', templates.data);
Step 2: Get Template Details
Retrieve details for a specific template:
const template = await client.contractTemplates.getContractById('template-id-here');
console.log('Template:', template.data);
console.log('Name:', template.data.name);
console.log('Network:', template.data.network);
Before deploying, understand what constructor parameters are required:
const constructorInfo = await client.contractTemplates.getContractConstructorById('template-id-here');
console.log('Constructor Parameters:', constructorInfo.data.parameters);
console.log('Parameter Types:', constructorInfo.data.parameters.map(p => ({
name: p.name,
type: p.type,
required: p.required
})));
Understanding Constructor Parameters
Constructor parameters are sent as an array of objects, where each object contains name, type, and value:
// Example constructor parameters structure
[
{
name: 'name', // Parameter name
type: 'string', // Parameter type
value: 'MyToken' // Parameter value
},
{
name: 'symbol',
type: 'string',
value: 'MTK'
},
{
name: 'initialSupply',
type: 'uint256',
value: '1000000'
}
]
The getContractConstructorById() method returns the constructor parameter definitions. Use those to build your constructorParameters array with the correct name, type, and value for each parameter.
Understand available functions on the contract:
// Get all functions
const functions = await client.contractTemplates.getContractFunctionById('template-id-here');
console.log('Available functions:', functions.data);
// Functions include both read and write operations
functions.data.forEach(func => {
console.log(`Function: ${func.name}`);
console.log(`Type: ${func.type}`); // 'read' or 'write'
console.log(`Parameters:`, func.parameters);
});
Step 5: Deploy Contract
Deploy the contract with your parameters:
const deployment = await client.contractTemplates.deployContract('template-id-here', {
network: 'ETH',
addressId: 'your-address-id',
clientShare: 'your-client-share',
constructorParameters: [
{ name: 'name', type: 'string', value: 'MyToken' },
{ name: 'symbol', type: 'string', value: 'MTK' },
{ name: 'initialSupply', type: 'uint256', value: '1000000' }
]
});
console.log('Deployment Workflow ID:', deployment.data.contractFunction?.workflowId);
Ensure constructor parameters match the types and order defined in the constructor info. Incorrect parameters will cause deployment to fail.
Step 6: Check Deployment Status
Deployment is async. Check workflow status:
const status = await client.temporal.getWorkflowStatus({
workflowId: deployment.data.contractFunction?.workflowId
});
console.log('Status:', status.data.status); // COMPLETED, RUNNING, FAILED
if (status.data.status === 'COMPLETED') {
console.log('Contract deployed at:', status.data.result.contractAddress);
console.log('Transaction Hash:', status.data.result.transactionHash);
} else if (status.data.status === 'FAILED') {
console.error('Deployment failed:', status.data.error);
}
Workflow Status Values
- RUNNING: Deployment in progress
- COMPLETED: Deployment successful
- FAILED: Deployment failed (check error details)
- CANCELLED: Deployment was cancelled
Step 7: Get Deployed Contract Details
Once deployment completes, retrieve contract details:
const deployedContract = await client.deployedContracts.getDeployedContract({
deploymentId: deployment.data.deploymentId
});
console.log('Contract Address:', deployedContract.data.contractAddress);
console.log('Network:', deployedContract.data.network);
console.log('Template ID:', deployedContract.data.templateId);
Step 8: Interact with Contract
After deployment, you can interact with the contract:
Read Functions
const result = await client.contractInteractions.readCallFunction(
'tETH',
deployedContract.data.contractAddress,
{
abiFunction: {
name: 'name',
type: 'function',
inputs: [],
outputs: [{ name: '', type: 'string' }]
}
}
);
console.log('Function result:', result.data.result?.data?.result);
Write Functions
const writeResult = await client.contractInteractions.writeCallFunction(
'tETH',
deployedContract.data.contractAddress,
{
addressId: 'your-address-id',
clientShare: 'your-client-share',
abiFunction: {
name: 'transfer',
type: 'function',
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' }
],
outputs: []
},
amount: '0',
feeLevel: 'standard'
}
);
console.log('Workflow ID:', writeResult.data.result?.workflowId);
// Check transaction receipt
const receipt = await client.contractInteractions.getTransactionReceipt({
network: 'ETH',
txId: writeResult.data.transactionHash
});
console.log('Transaction Status:', receipt.data.status);
Complete Example
Here’s a complete example:
import { OumlaSdkApiClient, OumlaSdkApiEnvironment } from '@oumla/sdk';
const client = new OumlaSdkApiClient({
environment: OumlaSdkApiEnvironment.Sandbox,
apiKey: process.env.OUMLA_API_KEY
});
async function deployContract() {
try {
// Step 1: Get templates
const templates = await client.contractTemplates.getContracts({
skip: 0,
take: 10
});
const template = templates.data[0]; // Use first template
console.log('Using template:', template.name);
// Step 2: Get constructor info
const constructorInfo = await client.contractTemplates.getContractConstructorById(template.id);
console.log('Constructor parameters:', constructorInfo.data.parameters);
// Step 3: Deploy contract
const deployment = await client.contractTemplates.deployContract(template.id, {
addressId: process.env.ADDRESS_ID,
clientShare: process.env.CLIENT_SHARE,
constructorParameters: [
// Map parameters based on constructor info
{ name: 'name', type: 'string', value: 'MyToken' },
{ name: 'symbol', type: 'string', value: 'MTK' }
]
});
console.log('Deployment started. Workflow ID:', deployment.data.workflowId);
// Step 4: Wait for deployment
let status;
do {
await new Promise(resolve => setTimeout(resolve, 3000));
status = await client.temporal.getWorkflowStatus({
workflowId: deployment.data.workflowId
});
console.log('Status:', status.data.status);
} while (status.data.status === 'RUNNING');
if (status.data.status === 'COMPLETED') {
const contractAddress = status.data.result.contractAddress;
console.log('Contract deployed at:', contractAddress);
// Step 5: Interact with contract
const name = await client.contractInteractions.readCallFunction({
network: template.network,
contractAddress: contractAddress,
functionName: 'name',
params: []
});
console.log('Contract name:', name.data.result);
}
} catch (error) {
console.error('Error:', error);
}
}
deployContract();
Managing Contract ABIs
Fetch ABI from Contract Address
const abi = await client.deployedContracts.fetchContractAbi({
network: 'ETH',
contractAddress: '0x...'
});
console.log('Contract ABI:', abi.data.abi);
Add Custom ABI
await client.deployedContracts.addContractAbi({
network: 'ETH',
contractAddress: '0x...',
abi: [
// Your ABI JSON array
]
});
Common Issues
Deployment Fails
Causes:
- Invalid constructor parameters
- Insufficient gas balance
- Network connectivity issues
Solutions:
- Verify constructor parameters match template requirements
- Ensure address has sufficient balance for gas
- Check network status and retry
Constructor Parameter Errors
Causes:
- Wrong parameter types
- Missing required parameters
- Parameter order mismatch
Solutions:
- Review constructor info carefully
- Ensure types match (string, uint256, address, etc.)
- Provide all required parameters
Function Call Fails
Causes:
- Function doesn’t exist
- Wrong parameter types
- Insufficient gas
Solutions:
- Verify function exists in contract ABI
- Check parameter types match function signature
- Ensure sufficient gas balance
Best Practices
- Always check constructor info before deploying
- Validate parameters before deployment
- Monitor workflow status until completion
- Store deployment IDs for future reference
- Handle errors gracefully - deployments can fail
- Test on testnet before mainnet deployment
- Verify contract address after deployment
Next Steps