Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Intermediate · 15 minutes or less

Split Contract Template with JavaScript

This tutorial is intended to help you call a Split Contract using Python. Templates are prebuilt TEAL programs that allow parameters to be injected into them from the SDKs that configure the contract. In this example, we are going to instantiate the Split Template and show how it can be used with a transaction.

Requirements

Background

Algorand provides many templates for Smart Contract implementation in the SDKs. The Split Contract is just one of the templates and is described in the reference documentation. Split Contracts are contract accounts that can disburse funds to two accounts with a defined ratio. Additionally, a minimum withdrawal amount can be set. If the funds are not claimed after a certain period of time, the original owner can reclaim the remaining funds.

Steps

1. Assign the Contract Receiver Accounts

The Split template can be instantiated with a set of predefined parameters that configure the Split contract. These parameters should not be confused with Transaction parameters that are passed into the contract when using the Split. These parameters configure how the Split will function:

  • TMPL_RCV1: the first recipient of the funds
  • TMPL_RCV2: the second recipient of the funds
  • TMPL_RAT1: for each TMPL_RAT2 microAlgos received by TMPL_RCV2, TMPL_RAT1 specifies how many are received by TMPL_RCV1
  • TMPL_RAT2: for each TMPL_RAT1 microAlgos received by TMPL_RCV1, TMPL_RAT2 specifies how many are received by TMPL_RCV2
  • TMPL_MINPAY: the minimum number of microAlgos that must be received by TMPL_RCV1 for a split withdrawal to succeed
  • TMPL_TIMEOUT: the round after which funds may be closed back to TMPL_OWN
  • TMPL_OWN: the address that funds may be closed to after TMPL_TIMEOUT
  • TMPL_FEE: the maximum fee that may be used by any individual transaction approved by this contract

So for example, if you want funds to be split such that for every 10 microAlgos, 3 will go to receiver 1 and 7 will go to receiver 2, TMPL_RAT1 will be set to 3 and TMPL_RAT2 will be set to 7. If the amount of a transaction can not be split with the desired ratio, the transactions will fail. The TMPL_MINPAY parameter must also be met for the transaction to succeed. So in this example, if TMPL_MINPAY was set to 3000, then the total transaction can be no less than 10000 microAlgos.

For this tutorial, we first need to define, the owner of the contract, and the two receivers.

// Handle importing needed modules
const algosdk = require('algosdk');
const fs = require('fs');
const splitTemplate = require("algosdk/src/logicTemplates/split");

// Retrieve the token, server and port values for your installation in the algod.net
// and algod.token files within the data directory
const token = "<your-api-token>";
const server = "http://<your-algod-host>";
const port = //<your-algod-port>;

// Split accounts for the sample
var account1_mnemonic = "portion never forward pill lunch organ biology" +
    " weird catch curve isolate plug innocent skin grunt" +
    " bounce clown mercy hole eagle soul chunk type absorb trim";
var account2_mnemonic = "place blouse sad pigeon wing warrior wild script" +
    " problem team blouse camp soldier breeze twist mother" +
    " vanish public glass code arrow execute convince ability" +
    " there";

// Instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);
(async() => {

    // Recover accounts to use with split contract
    // THQHGD4HEESOPSJJYYF34MWKOI57HXBX4XR63EPBKCWPOJG5KUPDJ7QJCM
    // AJNNFQN7DSR7QEY766V7JDG35OPM53ZSNF7CU264AWOOUGSZBMLMSKCRIU
    var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
    var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
    console.log(recoveredAccount1.addr);
    console.log(recoveredAccount2.addr);
    // This parameter defines who owns the contract
    let owner = "WO3QIJ6T4DZHBX5PWJH26JLHFSRT7W7M2DJOULPXDTUS6TUX7ZRIO4KDFY";

})().catch(e => {
    console.log(e);
});

2. Create Split Template

The Split template can now be instantiated with specific parameters.

// Handle importing needed modules
const algosdk = require('algosdk');
const fs = require('fs');
const splitTemplate = require("algosdk/src/logicTemplates/split");

// Retrieve the token, server and port values for your installation in the algod.net
// and algod.token files within the data directory
const token = "<your-api-token>";
const server = "http://<your-algod-host>";
const port = //<your-algod-port>;

// Split accounts for the sample
var account1_mnemonic = "portion never forward pill lunch organ biology" +
    " weird catch curve isolate plug innocent skin grunt" +
    " bounce clown mercy hole eagle soul chunk type absorb trim";
var account2_mnemonic = "place blouse sad pigeon wing warrior wild script" +
    " problem team blouse camp soldier breeze twist mother" +
    " vanish public glass code arrow execute convince ability" +
    " there";

// Instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);
(async() => {

    // Recover accounts to use with split contract
    // THQHGD4HEESOPSJJYYF34MWKOI57HXBX4XR63EPBKCWPOJG5KUPDJ7QJCM
    // AJNNFQN7DSR7QEY766V7JDG35OPM53ZSNF7CU264AWOOUGSZBMLMSKCRIU
    var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
    var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
    console.log(recoveredAccount1.addr);
    console.log(recoveredAccount2.addr);
    // This parameter defines who owns the contract
    let owner = "WO3QIJ6T4DZHBX5PWJH26JLHFSRT7W7M2DJOULPXDTUS6TUX7ZRIO4KDFY";

    // Inputs
    // Split contract should be two receivers in an
    // Atomic transfer
    let receivers = [recoveredAccount1.addr, recoveredAccount2.addr];
    // Receiver One gets 3/10 of whatever is in contract address
    // Receiver Two gets 7/10 of whatever is in contract address
    // The ratio is 3/7
    let ratn = parseInt(3);
    let ratd = parseInt(7);
    // At what round the contract expires
    // The ower can retreive leftover funds after this round
    let expiryRound = 5000000;
    // This parameter defines the minimum micro algos that receiver 1 gets
    let minPay = 3000;
    // protect the account so its not drained
    // with an excessive fee
    let maxFee = 2000;
    // Instaniate the template
    let split = new splitTemplate.Split(owner, receivers[0],
        receivers[1], ratn, ratd, expiryRound, minPay, maxFee);

    // Outputs
    // At this point you can write the program to file to be used
    // by someone who wants to sumbit a transaction against it
    let program = split.getProgram();
    console.log("split addr: " + split.getAddress());

})().catch(e => {
    console.log(e);
});

At this point, the split contract account must be funded before any transactions can be issued against it. Use the dispenser to do this now. Also, note that program bytes can be saved to use at a later time or in another application at this point.


Learn More
- Add Funds using Dispenser
- Smart Contracts - Contract Accounts

3. Create and Submit Transaction against Contract

The split contract template offers a helper method to create the proper transactions against the contract called getSplitFundsTransaction. This function takes an amount for the total transaction, creates two transactions (one for each receiver) and then groups these two transactions into an atomic transfer. These transactions are signed with the program logic and the function returns the resulting bytes to submit. These bytes can then be submitted to the blockchain.

// Handle importing needed modules
const algosdk = require('algosdk');
const fs = require('fs');
const splitTemplate = require("algosdk/src/logicTemplates/split");

// Retrieve the token, server and port values for your installation in the algod.net
// and algod.token files within the data directory
const token = "<your-api-token>";
const server = "http://<your-algod-host>";
const port = //<your-algod-port>;

// Split accounts for the sample
var account1_mnemonic = "portion never forward pill lunch organ biology" +
    " weird catch curve isolate plug innocent skin grunt" +
    " bounce clown mercy hole eagle soul chunk type absorb trim";
var account2_mnemonic = "place blouse sad pigeon wing warrior wild script" +
    " problem team blouse camp soldier breeze twist mother" +
    " vanish public glass code arrow execute convince ability" +
    " there";

// Instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);
(async() => {

    // Recover accounts to use with split contract
    // THQHGD4HEESOPSJJYYF34MWKOI57HXBX4XR63EPBKCWPOJG5KUPDJ7QJCM
    // AJNNFQN7DSR7QEY766V7JDG35OPM53ZSNF7CU264AWOOUGSZBMLMSKCRIU
    var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
    var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
    console.log(recoveredAccount1.addr);
    console.log(recoveredAccount2.addr);
    // This parameter defines who owns the contract
    let owner = "WO3QIJ6T4DZHBX5PWJH26JLHFSRT7W7M2DJOULPXDTUS6TUX7ZRIO4KDFY";

    // Inputs
    // Split contract should be two receivers in an
    // Atomic transfer
    let receivers = [recoveredAccount1.addr, recoveredAccount2.addr];
    // Receiver One gets 3/10 of whatever is in contract address
    // Receiver Two gets 7/10 of whatever is in contract address
    // The ratio is 3/7
    let ratn = parseInt(3);
    let ratd = parseInt(7);
    // At what round the contract expires
    // The ower can retreive leftover funds after this round
    let expiryRound = 5000000;
    // This parameter defines the minimum micro algos that receiver 1 gets
    let minPay = 3000;
    // protect the account so its not drained
    // with an excessive fee
    let maxFee = 2000;
    // Instaniate the template
    let split = new splitTemplate.Split(owner, receivers[0],
        receivers[1], ratn, ratd, expiryRound, minPay, maxFee);

    // Outputs
    // At this point you can write the program to file to be used
    // by someone who wants to sumbit a transaction against it
    let program = split.getProgram();
    console.log("split addr: " + split.getAddress());
    // Get the relevant params from the algod for the network
    let params = await algodclient.getTransactionParams();
    let endRound = params.lastRound + parseInt(1000);
    // create an atomic transfer based on the two recipients
    // which can be submitted in one operation 
    // The program can be read from a file if this is done 
    // in a separate application
    // The amount is the total to be split
    let txnBytes = splitTemplate.getSplitFundsTransaction(program, 1000000, 
                   params.lastRound, endRound, params.fee, params.genesishashb64);

    // Submit the transaction
    let tx = (await algodclient.sendRawTransaction(txnBytes));
    console.log( "txId: " + tx.txId );

})().catch(e => {
    console.log(e);
});


Learn More
- Atomic Transfers