Astroport
Search…
⌃K

Integrating Proxy Contracts

In this tutorial, we will cover integrating proxy contracts to enable third-party token rewards.

Prerequisites

  • Intro to Proxy Messages: Astro Generators
  • A liquidity mining mechanism to distribute your governance token to LPs in the Astroport pool. For new projects that want their liquidity mining mechanism to be integrated with Astroport, the simplest path is basing your liquidity mining contracts on the Mirror design. Alternatively, Anchor’s liquidity mining mechanism is simpler and should not require big changes to the example generator proxy contract.
  • A deployed generator proxy contract specific to your liquidity mining mechanism and Astroport pool. Astroport provides a proxy template that you can customize. Astroport also provides a full example proxy contract designed for the Mirror liquidity mining mechanism.

Code Overview

index.js
// setup
const { LCDClient, MnemonicKey, MsgExecuteContract } = require('@terra-money/terra.js');
async function main() {
const terra = new LCDClient({
URL: 'https://pisco-lcd.terra.dev',
chainID: 'pisco-1',
});
const mk = new MnemonicKey({
mnemonic: ''
});
const wallet = terra.wallet(mk);
// contract addresses (testnet)
const assembly_address = 'terra195m6n5xq4rkjy47fn5y3s08tfmj3ryknj55jqvgq2y55zul9myzsgy06hk';
const xastro_address = 'terra1ctzthkc0nzseppqtqlwq9mjwy9gq8ht2534rtcj3yplerm06snmqfc5ucr';
const generator_address = 'terra1ksvlfex49desf4c452j6dewdjs6c48nafemetuwjyj6yexd7x3wqvwa7j9';
const ex_proxy_addr = 'terra1y3pjn6g0awzpkme2nfp4nzu75ae6wuhdfztdn2pqju5tlzhkphjq5st2ts';
const ex_lp_addr = 'terra1s4ls0amk56vvfgv5jvsdacvr39r3a76p49wgplv0r27nxt7g3ugqpwul97';
// custom functions
async function queryContract(terra, contractAddress, query) {
return await terra.wasm.contractQuery(contractAddress, query);
}
function toEncodedBinary(object) {
return Buffer.from(JSON.stringify(object)).toString('base64');
}
// update generator config
let config = await queryContract(terra, generator_address, {config: {}});
config.allowed_reward_proxies.push(ex_proxy_addr);
// first msg
let msg = {
"set_allowed_reward_proxies": {
"proxies": config.allowed_reward_proxies
}
}
let binary = toEncodedBinary(msg)
let allow_proxies_msg = {
order: "1",
msg: {
wasm: {
execute: {
contract_addr: generator_address,
msg: binary,
funds: []
}
}
}
}
// second msg
let msg2 = {
"move_to_proxy": {
"lp_token": ex_lp_addr,
"proxy": ex_proxy_addr,
}
}
let binary2 = toEncodedBinary(msg2)
let move_to_proxy_msg = {
order: "2",
msg: {
wasm: {
execute: {
contract_addr: generator_address,
msg: binary2,
funds: []
}
}
}
}
// proposal msg
let proposal_msg = {
"submit_proposal": {
"title": "testing",
"description": "testing",
"link": null,
"messages": [allow_proxies_msg, move_to_proxy_msg]
}
}
let proposal_binary = toEncodedBinary(proposal_msg)
let execute_msg = {
"send": {
"contract": assembly_address,
"amount": "15000000000",
"msg": proposal_binary
}
}
// execute and broadcast proposal
let execute = new MsgExecuteContract(
wallet.key.accAddress,
xastro_address,
execute_msg,
);
let executeTx = await wallet.createAndSignTx({
msgs: [execute]
})
.then(tx => terra.tx.broadcast(tx))
.then((result) => console.log(result.txhash));
}
main().catch(console.error)

Step-by-Step

Set up

Note: This guide uses the pisco-1 testnet. For a complete guide to setting up Terra.js, visit here.
index.js
const { LCDClient, MnemonicKey, MsgExecuteContract } = require('@terra-money/terra.js');
async function main() {
const terra = new LCDClient({
URL: 'https://pisco-lcd.terra.dev',
chainID: 'pisco-1',
});
const mk = new MnemonicKey({
mnemonic: ''
});
const wallet = terra.wallet(mk);

Contract Addresses

We will be using the following 5 testnet addresses below in our proposal. For a full list of mainnet and testnet addresses, visit here. Note: The proposal expects a proxy address (your proxy contract must already be deployed).
index.js
const assembly_address = 'terra195m6n5xq4rkjy47fn5y3s08tfmj3ryknj55jqvgq2y55zul9myzsgy06hk';
const xastro_address = 'terra1ctzthkc0nzseppqtqlwq9mjwy9gq8ht2534rtcj3yplerm06snmqfc5ucr';
const generator_address = 'terra1ksvlfex49desf4c452j6dewdjs6c48nafemetuwjyj6yexd7x3wqvwa7j9';
const ex_proxy_addr = 'terra1y3pjn6g0awzpkme2nfp4nzu75ae6wuhdfztdn2pqju5tlzhkphjq5st2ts';
const ex_lp_addr = 'terra1s4ls0amk56vvfgv5jvsdacvr39r3a76p49wgplv0r27nxt7g3ugqpwul97';

Custom Functions

We will be using 2 custom functions. The first will allow us to query any contract, the second will allow us to encode our messages in binary format.
index.js
async function queryContract(terra, contractAddress, query) {
return await terra.wasm.contractQuery(contractAddress, query);
}
function toEncodedBinary(object) {
return Buffer.from(JSON.stringify(object)).toString('base64');
}

Update Generator Config

Next, we use our queryContract custom function to query the generator contract and return its config. The return value is saved to a config variable, which we update by pushing our new proxy address contract.
index.js
let config = await queryContract(terra, generator_address, {config: {}});
config.allowed_reward_proxies.push(ex_proxy_addr);

Allow Proxies Msg (1st Msg)

Currently, if you want to stake LP tokens to a proxy contract you have to:
  1. 1.
    Allow the proxy contract
  2. 2.
    Stake LP tokens
This is done in two separate messages which will be combined in our proposal. In this section, we will focus on the first message (allowing the proxy contract). Our msg takes in our updated config variable with our proxy contract address. We encode this message and pass it into our executable message.
index.js
let msg = {
"set_allowed_reward_proxies": {
"proxies": config.allowed_reward_proxies
}
}
let binary = toEncodedBinary(msg)
let allow_proxies_msg = {
order: "1",
msg: {
wasm: {
execute: {
contract_addr: generator_address,
msg: binary,
funds: []
}
}
}
}

Move to Proxy Msg (2nd Msg)

Next, we move our lp tokens to our proxy contract. We encode our message and pass it into our second executable message.
index.js
let msg2 = {
"move_to_proxy": {
"lp_token": ex_lp_addr,
"proxy": ex_proxy_addr,
}
}
let binary2 = toEncodedBinary(msg2)
let move_to_proxy_msg = {
order: "2",
msg: {
wasm: {
execute: {
contract_addr: generator_address,
msg: binary2,
funds: []
}
}
}
}

Proposal Msg

Now that we have our proxy messages, we can create a submit_proposal message and pass in our messages within an array [allow_proxies_msg, move_to_proxy_msg]. We encode our proposal message and pass our binary into a send message that will be sent to the xASTRO contract.
index.js
let proposal_msg = {
"submit_proposal": {
"title": "testing",
"description": "testing",
"link": null,
"messages": [allow_proxies_msg, move_to_proxy_msg]
}
}
let proposal_binary = toEncodedBinary(proposal_msg)
let execute_msg = {
"send": {
"contract": assembly_address,
"amount": "15000000000",
"msg": proposal_binary
}
}

Execute and Broadcast Transaction

Lastly, execute and broadcast the transaction.
index.js
let execute = new MsgExecuteContract(
wallet.key.accAddress,
xastro_address,
execute_msg,
);
let executeTx = await wallet.createAndSignTx({
msgs: [execute]
})
.then(tx => terra.tx.broadcast(tx))
.then((result) => console.log(result.txhash));
}
main().catch(console.error)
That’s it! Simply use the command line and node.js to execute the script and retrieve the transaction hash along with other information such as the proposal id.