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.


_10
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.

Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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.

Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The kind for this variable is an unsigned integer (uint).
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. This variable is named next_execution.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The .compose() method is called at the end of a chain of method calls indicating that the composer object is complete.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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.

Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The reward is set to the value returned by the reward estimator when passing it the message from the previous step.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The job is set to be recurring, and the reward and operational amount estimated earlier are inserted.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The variable, duration of the job, and the execution array (the condition and execute message) are specified for the job.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  1. The .compose() method is called to complete the job object.
Example.ts

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

  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

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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

_70
import { LCDClient, LCDClientConfig, MnemonicKey, Wallet } from '@terra-money/feather.js';
_70
import { uint, cond, fn, msg, variable, job, ts, WarpSdk } from '@terra-money/warp-sdk';
_70
_70
const piscoLcdClientConfig: LCDClientConfig = {
_70
lcd: 'https://pisco-lcd.terra.dev',
_70
chainID: 'pisco-1',
_70
gasAdjustment: 1.75,
_70
gasPrices: { uluna: 0.15 },
_70
prefix: 'terra',
_70
};
_70
_70
const lcd = new LCDClient({
_70
'pisco-1': piscoLcdClientConfig,
_70
});
_70
_70
const wallet = new Wallet(lcd, new MnemonicKey({ mnemonic: '<your mnemonic here>' }));
_70
_70
const sdk = new WarpSdk(wallet, piscoLcdClientConfig);
_70
const sender = wallet.key.accAddress(piscoLcdClientConfig.prefix);
_70
_70
const nextExecution = variable
_70
.static()
_70
.kind('uint')
_70
.name('next_execution')
_70
.value(ts.date(new Date('2023-04-10T12:30:00.000Z')))
_70
.onSuccess(fn.uint(uint.expr(uint.simple(ts.days(1)), 'add', uint.env('time'))))
_70
.onError(fn.uint(uint.expr(uint.simple(ts.hours(1)), 'add', uint.env('time'))))
_70
.compose();
_70
_70
const condition = cond.uint(uint.env('time'), 'gt', uint.ref(nextExecution));
_70
_70
const executions = [
_70
{
_70
condition,
_70
msgs: [msg.execute('terra10788fkzah89xrdm27zkj5yvhj9x3494lxawzm5qq3vvxcqz2yzaqyd3enk', { harvest: {} })],
_70
},
_70
];
_70
_70
const recurring = true;
_70
const durationDays = '30';
_70
const vars = [nextExecution];
_70
_70
const estimateJobRewardMsg = job
_70
.estimate()
_70
.recurring(recurring)
_70
.durationDays(durationDays)
_70
.vars(vars)
_70
.executions(executions)
_70
.compose();
_70
_70
const reward = await sdk.estimateJobReward(sender, estimateJobRewardMsg);
_70
_70
const operationalAmount = await sdk.estimateJobFee(sender, estimateJobRewardMsg, reward.amount.toString());
_70
_70
const createJobMsg = job
_70
.create()
_70
.name('eris-harvest')
_70
.description('This job harvests rewards for eris protocol vaults each day.')
_70
.labels([])
_70
.recurring(recurring)
_70
.reward(reward.amount.toString())
_70
.operationalAmount(operationalAmount.amount.toString())
_70
.vars(vars)
_70
.durationDays(durationDays)
_70
.executions(executions)
_70
.compose();
_70
_70
sdk.createJob(sender, createJobMsg, [operationalAmount]).then((response) => {
_70
console.log(response);
_70
});

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