var img = document.createElement('img'); img.src = "https://terradocs.matomo.cloud//piwik.php?idsite=1&rec=1&url=https://docs.terra.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

FeeShare registration

The x/FeeShare module allows smart contracts to receive a portion of the gas fees generated by interactions with the contract. Use this guide to learn how to register your contract and earn a portion of transaction fees. For more information on this module, visit the FeeShare spec.

Register an existing contract

Using Terrad

You can use Terrad to register your contract with the following commands. Be sure to use the appropriate flags when submitting the transaction.

The following command can only be used by the contract's admin. If the contract has no admin, only the creator can use it.

Terrad
Copy

_1
terrad tx feeshare [contract] [withdraw] --from [your_address]

To use the command, specify the following:

  • [contract]: The address of the deployed contract.
  • [withdraw]: An address to which the portion of the fee revenue will be sent.
  • [your_address]: The address of the signer.

Using a JSON message

The following example is a JSON message that can be sent to register a contract address in the FeeShare module.


_6
{
_6
"@type": "/juno.feeshare.v1.MsgRegisterFeeShare",
_6
"contract_address": "terra1w8ta7vhpzwe0y99tvvtp7k0k8uex2jq8jts8k2hsyg009ya06qts5fwftt",
_6
"deployer_address": "terra1880xn49l4x947pjv4a9k2qe5mf423kjzkn4ceu",
_6
"withdrawer_address": "terra1zdpgj8am5nqqvht927k3etljyl6a52kwqup0je"
_6
},

Using feather.js

  1. In this example, the first portion of the code is used to import the feather.js SDK, set up the accounts, and prepare the environment by initializing Terra's Light Client Daemon and setting up the wallets and accounts.
Example.ts
Copy

_31
import { LCDClient, MnemonicKey, MsgRegisterFeeShare } from "@terra-money/feather.js";
_31
_31
// Prepare environment clients, accounts and wallets
_31
const lcd = LCDClient.fromDefaultConfig("testnet");
_31
const mnemonic = new MnemonicKey({ mnemonic: "..." });
_31
const deployerAddr = mnemonic.accAddress("terra");
_31
const withdrawerAddr = mnemonic.accAddress("terra");
_31
const wallet = lcd.wallet(mnemonic);
_31
const contractAddr = "terra1eaxcahzxp0x8wqejqjlqaey53tp06l728qad6z395lyzgl026qkq20xj43";
_31
_31
_31
(async () => {
_31
try {
_31
// Submit a transaction to register the feeshare
_31
let tx = await wallet.createAndSignTx({
_31
msgs: [new MsgRegisterFeeShare(
_31
contractAddr,
_31
deployerAddr,
_31
withdrawerAddr,
_31
)],
_31
chainID: "pisco-1",
_31
memo: "Registering feeshare #TerraDevs",
_31
});
_31
let result = await lcd.tx.broadcastSync(tx, "test-1");
_31
_31
console.log("Transaction Hash", result.txhash)
_31
}
_31
catch (e) {
_31
console.log(e)
_31
}
_31
})()

  1. Next, a contract is registered with the FeeShare module by executing a MsgRegisterFeeShare transaction. This message is created by supplying it with the following addresses:

    • contractAddress: The address of the deployed contract.
    • deployerAddress: The address of the deployer of the contract.
    • withdrawerAddress: An address to which the portion of the fee revenue will be sent.
Example.ts
Copy

_31
import { LCDClient, MnemonicKey, MsgRegisterFeeShare } from "@terra-money/feather.js";
_31
_31
// Prepare environment clients, accounts and wallets
_31
const lcd = LCDClient.fromDefaultConfig("testnet");
_31
const mnemonic = new MnemonicKey({ mnemonic: "..." });
_31
const deployerAddr = mnemonic.accAddress("terra");
_31
const withdrawerAddr = mnemonic.accAddress("terra");
_31
const wallet = lcd.wallet(mnemonic);
_31
const contractAddr = "terra1eaxcahzxp0x8wqejqjlqaey53tp06l728qad6z395lyzgl026qkq20xj43";
_31
_31
_31
(async () => {
_31
try {
_31
// Submit a transaction to register the feeshare
_31
let tx = await wallet.createAndSignTx({
_31
msgs: [new MsgRegisterFeeShare(
_31
contractAddr,
_31
deployerAddr,
_31
withdrawerAddr,
_31
)],
_31
chainID: "pisco-1",
_31
memo: "Registering feeshare #TerraDevs",
_31
});
_31
let result = await lcd.tx.broadcastSync(tx, "test-1");
_31
_31
console.log("Transaction Hash", result.txhash)
_31
}
_31
catch (e) {
_31
console.log(e)
_31
}
_31
})()

  1. In this example, the first portion of the code is used to import the feather.js SDK, set up the accounts, and prepare the environment by initializing Terra's Light Client Daemon and setting up the wallets and accounts.
  1. Next, a contract is registered with the FeeShare module by executing a MsgRegisterFeeShare transaction. This message is created by supplying it with the following addresses:

    • contractAddress: The address of the deployed contract.
    • deployerAddress: The address of the deployer of the contract.
    • withdrawerAddress: An address to which the portion of the fee revenue will be sent.
Example.ts
CopyExpandClose

_31
import { LCDClient, MnemonicKey, MsgRegisterFeeShare } from "@terra-money/feather.js";
_31
_31
// Prepare environment clients, accounts and wallets
_31
const lcd = LCDClient.fromDefaultConfig("testnet");
_31
const mnemonic = new MnemonicKey({ mnemonic: "..." });
_31
const deployerAddr = mnemonic.accAddress("terra");
_31
const withdrawerAddr = mnemonic.accAddress("terra");
_31
const wallet = lcd.wallet(mnemonic);
_31
const contractAddr = "terra1eaxcahzxp0x8wqejqjlqaey53tp06l728qad6z395lyzgl026qkq20xj43";
_31
_31
_31
(async () => {
_31
try {
_31
// Submit a transaction to register the feeshare
_31
let tx = await wallet.createAndSignTx({
_31
msgs: [new MsgRegisterFeeShare(
_31
contractAddr,
_31
deployerAddr,
_31
withdrawerAddr,
_31
)],
_31
chainID: "pisco-1",
_31
memo: "Registering feeshare #TerraDevs",
_31
});
_31
let result = await lcd.tx.broadcastSync(tx, "test-1");
_31
_31
console.log("Transaction Hash", result.txhash)
_31
}
_31
catch (e) {
_31
console.log(e)
_31
}
_31
})()

Register a new contract

Use the following example to instantiate your contract and register with the FeeShare module.

Setup

  1. The first portion of the code is used to import the necessary functions, classes, and objects from the feather.js SDK.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

  1. The next few lines prepare the environment by initializing Terra's Light Client Daemon and setting up the wallets and accounts.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

Deploy the contract

  1. This code creates and signs a transaction to store the smart contract on the blockchain. It waits for the transaction to be completed and gets the contract's code id from the result.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

  1. A contract instantiation message is created and signed to deploy the contract to the blockchain. The contract has an initial balance of 1uluna. It waits for the transaction to be completed and gets the contract address from the result.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

Register with the FeeShare module

The contract is registered with the FeeShare module by executing a MsgRegisterFeeShare transaction. This message is created by supplying it with the following addresses:

  • contractAddress: The address of the deployed contract.
  • deployerAddress: The address of the deployer of the contract.
  • withdrawerAddress: An address to which the portion of the fee revenue will be sent.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

Check for fees

  1. In this example, a transaction is created by executing the sample contract's change_owner message along with a fee of 400000uluna for the transaction.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

  1. To check that the FeeShare is working properly, the withdrawer_address is queried. In this code, the expected portion of fees sent to a contract's registered withdrawer_address is 0.500000000000000000, or half of the fees. If the module is working properly, half of the fees (200000uluna) are expected to be sent to the withdrawer_address.
Example.ts
Copy

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()

Setup

  1. The first portion of the code is used to import the necessary functions, classes, and objects from the feather.js SDK.
  1. The next few lines prepare the environment by initializing Terra's Light Client Daemon and setting up the wallets and accounts.

Deploy the contract

  1. This code creates and signs a transaction to store the smart contract on the blockchain. It waits for the transaction to be completed and gets the contract's code id from the result.
  1. A contract instantiation message is created and signed to deploy the contract to the blockchain. The contract has an initial balance of 1uluna. It waits for the transaction to be completed and gets the contract address from the result.

Register with the FeeShare module

The contract is registered with the FeeShare module by executing a MsgRegisterFeeShare transaction. This message is created by supplying it with the following addresses:

  • contractAddress: The address of the deployed contract.
  • deployerAddress: The address of the deployer of the contract.
  • withdrawerAddress: An address to which the portion of the fee revenue will be sent.

Check for fees

  1. In this example, a transaction is created by executing the sample contract's change_owner message along with a fee of 400000uluna for the transaction.
  1. To check that the FeeShare is working properly, the withdrawer_address is queried. In this code, the expected portion of fees sent to a contract's registered withdrawer_address is 0.500000000000000000, or half of the fees. If the module is working properly, half of the fees (200000uluna) are expected to be sent to the withdrawer_address.
Example.ts
CopyExpandClose

_89
import { getMnemonics } from "../helpers/mnemonics";
_89
import { getLCDClient } from "../helpers/lcd.connection";
_89
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
_89
import { blockInclusion } from "../helpers/const";
_89
import fs from "fs";
_89
import path from 'path';
_89
_89
// Prepare environment clients, accounts and wallets
_89
const LCD = getLCDClient();
_89
const accounts = getMnemonics();
_89
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
_89
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
_89
const withdrawerAddress = new MnemonicKey().accAddress("terra");
_89
let contractAddress: string;
_89
_89
(async () => {
_89
// Read the reflect contract, store it on chain and
_89
// read the code id from the result...
_89
let tx = await wallet.createAndSignTx({
_89
msgs: [new MsgStoreCode(
_89
deployerAddress,
_89
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
_89
expect(codeId).toBeDefined();
_89
_89
// ... then instantiate the reflect contract
_89
// wait for the block inclusion and read the
_89
// contract adddress from the result logs
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgInstantiateContract(
_89
deployerAddress,
_89
deployerAddress,
_89
codeId,
_89
{},
_89
Coins.fromString("1uluna"),
_89
"Reflect contract " + Math.random(),
_89
)],
_89
chainID: "test-1",
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
_89
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
_89
_89
// Submit a transaction to register the feeshare
_89
tx = await wallet.createAndSignTx({
_89
msgs: [new MsgRegisterFeeShare(
_89
contractAddress,
_89
deployerAddress,
_89
withdrawerAddress,
_89
)],
_89
chainID: "test-1",
_89
});
_89
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
// Send an execute message to the reflect contract
_89
let msgExecute = new MsgExecuteContract(
_89
deployerAddress,
_89
contractAddress,
_89
{
_89
change_owner: {
_89
owner: withdrawerAddress,
_89
}
_89
},
_89
);
_89
tx = await wallet.createAndSignTx({
_89
msgs: [msgExecute],
_89
chainID: "test-1",
_89
fee: new Fee(200_000, "400000uluna"),
_89
});
_89
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
_89
await blockInclusion();
_89
_89
_89
// Query the withdrawer adddress (new owner of the contract)
_89
// and validate that the account has received 50% of the fees
_89
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
_89
expect(bankAmount[0])
_89
.toMatchObject(Coins.fromString("200000uluna"))
_89
})()