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.
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 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.
The following example is a JSON message that can be sent to register a contract address in the FeeShare module.
{
"@type": "/juno.feeshare.v1.MsgRegisterFeeShare",
"contract_address": "terra1w8ta7vhpzwe0y99tvvtp7k0k8uex2jq8jts8k2hsyg009ya06qts5fwftt",
"deployer_address": "terra1880xn49l4x947pjv4a9k2qe5mf423kjzkn4ceu",
"withdrawer_address": "terra1zdpgj8am5nqqvht927k3etljyl6a52kwqup0je"
},
<CH.Scrollycoding>
- 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.
import { LCDClient, MnemonicKey, MsgRegisterFeeShare } from "@terra-money/feather.js";
// Prepare environment clients, accounts and wallets
const lcd = LCDClient.fromDefaultConfig("testnet");
const mnemonic = new MnemonicKey({ mnemonic: "..." });
const deployerAddr = mnemonic.accAddress("terra");
const withdrawerAddr = mnemonic.accAddress("terra");
const wallet = lcd.wallet(mnemonic);
const contractAddr = "terra1eaxcahzxp0x8wqejqjlqaey53tp06l728qad6z395lyzgl026qkq20xj43";
(async () => {
try {
// Submit a transaction to register the feeshare
let tx = await wallet.createAndSignTx({
msgs: [new MsgRegisterFeeShare(
contractAddr,
deployerAddr,
withdrawerAddr,
)],
chainID: "pisco-1",
memo: "Registering feeshare #TerraDevs",
});
let result = await lcd.tx.broadcastSync(tx, "test-1");
console.log("Transaction Hash", result.txhash)
}
catch (e) {
console.log(e)
}
})()
-
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.
</CH.Scrollycoding>
Use the following example to instantiate your contract and register with the FeeShare module.
<CH.Scrollycoding>
- The first portion of the code is used to import the necessary functions, classes, and objects from the feather.js SDK.
import { getMnemonics } from "../helpers/mnemonics";
import { getLCDClient } from "../helpers/lcd.connection";
import { Coins, Fee, MnemonicKey, MsgExecuteContract, MsgInstantiateContract, MsgRegisterFeeShare, MsgStoreCode } from "@terra-money/feather.js";
import { blockInclusion } from "../helpers/const";
import fs from "fs";
import path from 'path';
// Prepare environment clients, accounts and wallets
const LCD = getLCDClient();
const accounts = getMnemonics();
const wallet = LCD.chain1.wallet(accounts.feeshareMnemonic);
const deployerAddress = accounts.feeshareMnemonic.accAddress("terra");
const withdrawerAddress = new MnemonicKey().accAddress("terra");
let contractAddress: string;
(async () => {
// Read the reflect contract, store it on chain and
// read the code id from the result...
let tx = await wallet.createAndSignTx({
msgs: [new MsgStoreCode(
deployerAddress,
fs.readFileSync(path.join(__dirname, "/../contracts/reflect.wasm")).toString("base64"),
)],
chainID: "test-1",
});
let result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
await blockInclusion();
let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
let codeId = Number(txResult.logs[0].events[1].attributes[1].value);
expect(codeId).toBeDefined();
// ... then instantiate the reflect contract
// wait for the block inclusion and read the
// contract adddress from the result logs
tx = await wallet.createAndSignTx({
msgs: [new MsgInstantiateContract(
deployerAddress,
deployerAddress,
codeId,
{},
Coins.fromString("1uluna"),
"Reflect contract " + Math.random(),
)],
chainID: "test-1",
});
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
await blockInclusion();
txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any;
contractAddress = txResult.logs[0].eventsByType.instantiate._contract_address[0];
// Submit a transaction to register the feeshare
tx = await wallet.createAndSignTx({
msgs: [new MsgRegisterFeeShare(
contractAddress,
deployerAddress,
withdrawerAddress,
)],
chainID: "test-1",
});
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
await blockInclusion();
// Send an execute message to the reflect contract
let msgExecute = new MsgExecuteContract(
deployerAddress,
contractAddress,
{
change_owner: {
owner: withdrawerAddress,
}
},
);
tx = await wallet.createAndSignTx({
msgs: [msgExecute],
chainID: "test-1",
fee: new Fee(200_000, "400000uluna"),
});
result = await LCD.chain1.tx.broadcastSync(tx, "test-1");
await blockInclusion();
// Query the withdrawer adddress (new owner of the contract)
// and validate that the account has received 50% of the fees
const bankAmount = await LCD.chain1.bank.balance(withdrawerAddress);
expect(bankAmount[0])
.toMatchObject(Coins.fromString("200000uluna"))
})()
- The next few lines prepare the environment by initializing Terra's Light Client Daemon and setting up the wallets and accounts.
- 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.
- 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.
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.
- In this example, a transaction is created by executing the sample contract's
change_owner
message along with a fee of400000uluna
for the transaction.
- 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 registeredwithdrawer_address
is0.500000000000000000
, or half of the fees. If the module is working properly, half of the fees (200000uluna
) are expected to be sent to thewithdrawer_address
.
</CH.Scrollycoding>