var img = document.createElement('img'); img.src = "https://terradocs.matomo.cloud//piwik.php?idsite=3&rec=1&url=https://docs.warp.money" + location.pathname; img.style = "border:0"; img.alt = "tracker"; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(img,s);
Skip to main content

Warp SDK tutorial

The Warp SDK provides a simple way to interact with the Warp protocol's contracts. Developers can use the Warp SDK to easily create jobs, conditions, and variables in a typesafe environment. You can use the autocomplete functions in your IDE to help you get the most out of using the Warp SDK.

Installation

Run the following code to install the Warp SDK. You may also need to install feather.js (Terra's JavaScript SDK) or the SDK of the chain you are using.

npm install -S @terra-money/warp-sdk

Example

The following example will walk you through the creation of variables, conditions, and jobs using the SDK.

This code outlines a job that harvests rewards for the Eris protocol every day. The basic logic of the job can be stated as follows:

If the current time is greater than the next execution time, execute the harvest message.

The job is set as recurring, meaning that it will be requeued after execution.

Setup

The first portion of the code is used to import the feather.js SDK and the Warp SDK, connect to the blockchain network, and set up the wallet object.

Expand for more information about setup.


  1. The first 2 lines import the feather.js SDK and the Warp SDK. These libraries provide all the functionality for your job.

  2. Lines 4-14 initialize the Terra testnet LCD. Terra’s Light Client Daemon allows you to connect to the blockchain, make queries, create wallets, and submit transactions. The configuration specifies the network information needed for Terra's Pisco testnet.

  3. Line 16 adds a wallet object, allowing you to connect your account by entering your mnemonic. In production, it's better to store your mnemonic key data in your environment by using process.env.SECRET_MNEMONIC or process.env.SECRET_PRIV_KEY. This practice is more secure than a hard-coded string.

  4. Lines 18-19 initialize the Warp SDK and specify the sender of the job as the connected wallet account.

The variable

  1. Because this job needs to be run every day, it requires a variable. Every time the job is run successfully, the execution time variable will be incremented by one day. Just like in other programming languages, you can provide variables in the Warp SDK that can be updated.
  1. nextExecution is declared as a variable, which initializes the SDK's variable composer. Type a period after variable to view the available method options using your IDE's autocompletion.
  1. This variable is static because it needs to be an updatable value. The other two types of variables are query and external, which aren't needed for this job.
  1. The kind for this variable is an unsigned integer (uint).
  1. This variable is named next_execution.
  1. Next, the variable is given an initial value. This value will be set to the time and date of the first harvest. The timestamp composer is called using ts.date, which takes in a JavaScript Date object as a parameter and returns a timestamp.
  1. This code is the logic for updating the next_execution variable. The .onSuccess() method dictates that upon completion of a successful job, the next_execution timestamp value will be increased by 1 day by using an update function.
  1. Similarly, if the job returns an error upon execution, the timestamp value will be increased by an hour, and the job will run again.
  1. The .compose() method is called at the end of a chain of method calls indicating that the composer object is complete.

The condition

  1. The cond composer is used to create a conditional expression. It takes three arguments: a left side value, an operator, and a right side value.

  2. The condition for this job is simple: if the current time is greater than the value of the next_execution variable, execute the job message.

The job

  1. Now it's time to create the job execution message, which is the message that will be executed when the condition is met.
  1. The executions array contains the condition and execute message for the job. This array can be used for single or multiple condition/job pairs, operating as a switch. If the array contains multiple pairs, the conditions will be run top-down. Only the first pair whose condition returns as true will be executed.
  1. In this example, there is only one condition and job pair set. The condition set earlier is referenced, and below that, the execute message for the job is set, containing the contract's address and the {harvest: {}} message.
  1. The job is set to be recurring, which means it will be re-added to the queue after execution. The duration of the recurrence is set to run for 30 days, and the next_execution variable is specified to be updated upon requeuing.
  1. In order to pay for the job fees and reward the keeper for execution, the job reward needs to be estimated. Using the job composer, the estimate specifies all the attributes of the job, including the fact that it is recurring, its duration, any variables, and the contents of the execution array. The .compose() method is called to complete the job object.
  1. The reward is set to the value returned by the reward estimator when passing it the message from the previous step.
  1. The other job fees are estimated and set by passing estimateJobRewardMsg and the reward calculated in the previous step to the job fee estimator.
  1. The job is created by putting together all the previous information using the job composer. The create method is used to create a new job instance for your job. A name, description, and optional labels give information about the job and what it does.
  1. The job is set to be recurring, and the reward and operational amount estimated earlier are inserted.
  1. The variable, duration of the job, and the execution array (the condition and execute message) are specified for the job.
  1. The .compose() method is called to complete the job object.
  1. The code is finished by adding the createJob method, specifying the createJobMsg, the sender, and the operationalAmount, and asking for the response.
Example.ts
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';

const piscoLcdClientConfig: LCDClientConfig = {
lcd: 'https://pisco-lcd.terra.dev',
chainID: 'pisco-1',
gasAdjustment: 1.75,
gasPrices: { uluna: 0.15 },
prefix: 'terra',
};

const lcd = new LCDClient({
'pisco-1': piscoLcdClientConfig,
});

const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));

const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);

const nextExecution = variable
.static()
.kind('uint')
.name('next_execution')
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
.compose();

const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));

const executions = [
{
condition,
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
},
];

const recurring = true;
const durationDays = '30';
const vars = [nextExecution];

const estimateJobRewardMsg = job
.estimate()
.recurring(recurring)
.durationDays(durationDays)
.vars(vars)
.executions(executions)
.compose();

const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);

const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());

const createJobMsg = job
.create()
.name('eris-harvest')
.description('This job harvests rewards for eris protocol vaults each day.')
.labels([])
.recurring(recurring)
.reward(reward.amount.toString())
.operationalAmount(operationalAmount.amount.toString())
.vars(vars)
.durationDays(durationDays)
.executions(executions)
.compose();

sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
console.log(response);
});

Congratulations, you have just walked through an entire job created using the Warp SDK!