Skip to main content
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:
  1. Create or Select Template - Use an existing template or create a new one
  2. Get Constructor Info - Understand required constructor parameters
  3. Deploy Contract - Deploy with your parameters
  4. Check Status - Monitor the async deployment workflow
  5. 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);

Step 3: Get Constructor Information

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.

Step 4: Get Function Information

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

  1. Always check constructor info before deploying
  2. Validate parameters before deployment
  3. Monitor workflow status until completion
  4. Store deployment IDs for future reference
  5. Handle errors gracefully - deployments can fail
  6. Test on testnet before mainnet deployment
  7. Verify contract address after deployment

Next Steps