Chapter 2
Estimated time: 1 hr 30 mins
This chapter serves as a brief guide on how to utilize the pricefeed module in your Cosmos SDK app.
Be sure you have met the prerequisites before you follow this tutorial.
sudo apt update && sudo apt install build-essential
To create a new blockchain project with Ignite, you will need to run the following command:
ignite scaffold chain example
The ignite scaffold chain command will create a new blockchain in a new directory example.
To expedite the testing of the pricefeed module, modify the default voting period to 40 seconds by incorporating this code in example/config.yml
.
... genesis: app_state: gov: params: voting_period: "40s"
go install github.com/bandprotocol/oracle-consumer
import ( ... pricefeedclient "github.com/bandprotocol/oracle-consumer/x/pricefeed/client" ) func getGovProposalHandlers() []govclient.ProposalHandler { var govProposalHandlers []govclient.ProposalHandler govProposalHandlers = append( ... pricefeedclient.ProposalHandler, ) return govProposalHandlers }
import ( ... pricefeed "github.com/bandprotocol/oracle-consumer/x/pricefeed" ) ModuleBasics = module.NewBasicManager( ... pricefeed.AppModuleBasic{}, )
import ( ... pricefeedkeeper "github.com/bandprotocol/oracle-consumer/x/pricefeed/keeper" ) type BandApp struct { ... scopedpricefeedKeeper capabilitykeeper.ScopedKeeper pricefeedKeeper pricefeedkeeper.Keeper }
keys := sdk.NewKVStoreKeys( ... pricefeedtypes.StoreKey, )
scopedpricefeedKeeper := app.CapabilityKeeper.ScopeToModule(pricefeedtypes.ModuleName) app.scopedpricefeedKeeper = scopedpricefeedKeeper app.pricefeedKeeper = *pricefeedkeeper.NewKeeper( appCodec, keys[pricefeedtypes.StoreKey], keys[pricefeedtypes.MemStoreKey], app.GetSubspace(pricefeedtypes.ModuleName), app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, scopedpricefeedKeeper, )
pricefeedModule := pricefeedmodule.NewAppModule(appCodec, app.pricefeedKeeper, app.AccountKeeper, app.BankKeeper) pricefeedIBCModule := pricefeedmodule.NewIBCModule(app.pricefeedKeeper)
govRouter. AddRoute(...). AddRoute(pricefeedtypes.RouterKey, pricefeedmodule.NewUpdateSymbolRequestProposalHandler(app.pricefeedKeeper))
app.mm = module.NewManager( ..., pricefeedModule, )
app.mm.SetOrderBeginBlockers( ..., pricefeedtypes.ModuleName, ) app.mm.SetOrderEndBlockers( ..., pricefeedtypes.ModuleName, ) app.mm.SetOrderInitGenesis( pricefeedtypes.ModuleName, )
app.sm = module.NewSimulationManager( ... pricefeedModule, )
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(...) paramsKeeper.Subspace(pricefeedmoduletypes.ModuleName) // this line is used by starport scaffolding # stargate/app/paramSubspace return paramsKeeper }
You have completed importing the pricefeed module and can now execute the chain by running this command :tada:
ignite chain serve -v
The second step is to set up a relayer to listen and relay IBC packets between a your chain and BandChain.
Here are the simple guides for setting up a relayer.
This tutorial will use the Hermes relayer by adhering to the following steps.
# Clone Hermes version 1.4.0 git clone https://github.com/informalsystems/hermes.git cd hermes git checkout v1.4.0 # Build Hermes cargo build --release
# hermes/ touch config_relayer.toml
add the Hermes config in config_relayer.toml
# The global section has parameters that apply globally to the relayer operation. [global] # Specify the verbosity for the relayer logging output. Default: 'info' # Valid options are 'error', 'warn', 'info', 'debug', 'trace'. log_level = 'trace' # Specify the mode to be used by the relayer. [Required] [mode] # Specify the client mode. [mode.clients] # Whether or not to enable the client workers. [Required] enabled = true # Whether or not to enable periodic refresh of clients. [Default: true] # Note: Even if this is disabled, clients will be refreshed automatically if # there is activity on a connection or channel they are involved with. refresh = true # Whether or not to enable misbehaviour detection for clients. [Default: false] misbehaviour = true # Specify the connections mode. [mode.connections] # Whether or not to enable the connection workers for handshake completion. [Required] enabled = true # Specify the channels mode. [mode.channels] # Whether or not to enable the channel workers for handshake completion. [Required] enabled = true # Specify the packets mode. [mode.packets] # Whether or not to enable the packet workers. [Required] enabled = true # Parametrize the periodic packet clearing feature. # Interval (in number of blocks) at which pending packets # should be eagerly cleared. A value of '0' will disable # periodic packet clearing. [Default: 100] clear_interval = 100 # Whether or not to clear packets on start. [Default: false] clear_on_start = true # Toggle the transaction confirmation mechanism. # The tx confirmation mechanism periodically queries the `/tx_search` RPC # endpoint to check that previously-submitted transactions # (to any chain in this config file) have delivered successfully. # Experimental feature. Affects telemetry if set to false. # [Default: true] tx_confirmation = true # The REST section defines parameters for Hermes' built-in RESTful API. # https://hermes.informal.systems/rest.html [rest] # Whether or not to enable the REST service. Default: false enabled = true # Specify the IPv4/6 host over which the built-in HTTP server will serve the RESTful # API requests. Default: 127.0.0.1 host = '127.0.0.1' # Specify the port over which the built-in HTTP server will serve the restful API # requests. Default: 3000 port = 3000 # The telemetry section defines parameters for Hermes' built-in telemetry capabilities. # https://hermes.informal.systems/telemetry.html [telemetry] # Whether or not to enable the telemetry service. Default: false enabled = true # Specify the IPv4/6 host over which the built-in HTTP server will serve the metrics # gathered by the telemetry service. Default: 127.0.0.1 host = '127.0.0.1' # Specify the port over which the built-in HTTP server will serve the metrics gathered # by the telemetry service. Default: 3001 port = 3001 [[chains]] id = 'example' rpc_addr = 'http://localhost:26657' grpc_addr = 'http://localhost:9090' websocket_addr = 'ws://localhost:26657/websocket' rpc_timeout = '10s' account_prefix = 'cosmos' key_name = 'requester' store_prefix = 'ibc' default_gas = 5000000 max_gas = 15000000 gas_price = { price = 0, denom = 'ustake' } gas_multiplier = 1.1 max_msg_num = 20 max_tx_size = 209715 clock_drift = '20s' max_block_time = '10s' trusting_period = '10days' trust_threshold = { numerator = '1', denominator = '3' } address_type = { derivation = 'cosmos' } ignore_port_channel = [] # [chains.packet_filter] # policy = 'allow' # list = [ # ['wasm.*', '*'], # ] [[chains]] id = 'band-laozi-testnet6' rpc_addr = 'https://rpc.laozi-testnet6.bandchain.org:443' grpc_addr = 'https://laozi-testnet6.bandchain.org:443' websocket_addr = 'wss://rpc.laozi-testnet6.bandchain.org:443/websocket' rpc_timeout = '10s' account_prefix = 'band' key_name = 'testkey' store_prefix = 'ibc' default_gas = 100000 max_gas = 10000000 gas_price = { price = 0.0025, denom = 'uband' } gas_multiplier = 1.1 max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' max_block_time = '10s' trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } address_type = { derivation = 'cosmos' } ignore_port_channel = [] # [chains.packet_filter] # policy = 'allow' # list = [ # ['oracle', '*'], # ]
Note: Upon logging for the first time that you run example chain, you will be given either Alice's or Bob's mnemonic, which can be used as the consumer mnemonic. It's important to note that you need to have funds in your key in order to send transactions on each chain.
# hermes/ touch mem-example.txt
# hermes/ touch mem-band.txt
target/release/hermes --config config_relayer.toml keys add --chain example --mnemonic-file "mem-example.txt"
target/release/hermes --config config_relayer.toml keys add --chain band-laozi-testnet6 --mnemonic-file "mem-band.txt" --hd-path "m/44'/494'/0'/0/0"
target/release/hermes --config config_relayer.toml create channel --a-chain band-laozi-testnet6 --b-chain example --a-port oracle --b-port pricefeed --order unordered --channel-version bandchain-1 --new-client-connection
target/release/hermes --config config_relayer.toml start
The purpose of this proposal is to request price data from BandChain at block_interval
specified in the proposal. If the proposal is approved, the pricefeed module will retrieve the data and store the response on the consumer chain.
{ "title": "Update Symbol requests", "description": "Update symbol that request price from BandChain", "symbol_requests": [ { "symbol": "BTC", "oracle_script_id": "396", "block_interval": "40" }, { "symbol": "ETH", "oracle_script_id": "396", "block_interval": "40" } ], "deposit": "10000000stake" }
exampled tx gov submit-legacy-proposal update-symbol-request proposal.json --from alice
exampled tx gov vote 1 yes --from alice
exampled tx gov vote 1 yes --from bob
exampled query gov proposals
Once the proposal has been approved, the pricefeed module will query BTC and ETH from BandChain every 40 blocks on your chain, and you can view the latest price by executing this command.
exampled query pricefeed price BTC