faucet: remove module (#678)
* changelog v0.4.0 * faucet: remove module * changelog * codecov
This commit is contained in:
parent
153478eb69
commit
4a619b1e1b
@ -39,12 +39,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (faucet) [\#678](https://github.com/cosmos/ethermint/pull/678) Faucet module has been removed in favor of client libraries such as [`@cosmjs/faucet`](https://github.com/cosmos/cosmjs/tree/master/packages/faucet).
|
||||
* (evm) [\#670](https://github.com/cosmos/ethermint/pull/670) Migrate types to the ones defined by the protobuf messages, which are required for the stargate release.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot
|
||||
* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent
|
||||
* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent.
|
||||
* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot.
|
||||
|
||||
## [v0.4.0] - 2020-12-15
|
||||
|
||||
|
@ -30,7 +30,6 @@ import (
|
||||
ethermintcodec "github.com/cosmos/ethermint/codec"
|
||||
ethermint "github.com/cosmos/ethermint/types"
|
||||
"github.com/cosmos/ethermint/x/evm"
|
||||
"github.com/cosmos/ethermint/x/faucet"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@ -74,7 +73,6 @@ var (
|
||||
evidence.AppModuleBasic{},
|
||||
upgrade.AppModuleBasic{},
|
||||
evm.AppModuleBasic{},
|
||||
faucet.AppModuleBasic{},
|
||||
)
|
||||
|
||||
// module account permissions
|
||||
@ -85,7 +83,6 @@ var (
|
||||
staking.BondedPoolName: {supply.Burner, supply.Staking},
|
||||
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
|
||||
gov.ModuleName: {supply.Burner},
|
||||
faucet.ModuleName: {supply.Minter},
|
||||
}
|
||||
|
||||
// module accounts that are allowed to receive tokens
|
||||
@ -126,7 +123,6 @@ type EthermintApp struct {
|
||||
ParamsKeeper params.Keeper
|
||||
EvidenceKeeper evidence.Keeper
|
||||
EvmKeeper *evm.Keeper
|
||||
FaucetKeeper faucet.Keeper
|
||||
|
||||
// the module manager
|
||||
mm *module.Manager
|
||||
@ -157,7 +153,7 @@ func NewEthermintApp(
|
||||
bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
||||
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
||||
gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey,
|
||||
evm.StoreKey, faucet.StoreKey,
|
||||
evm.StoreKey,
|
||||
)
|
||||
|
||||
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
|
||||
@ -215,9 +211,6 @@ func NewEthermintApp(
|
||||
app.EvmKeeper = evm.NewKeeper(
|
||||
app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper,
|
||||
)
|
||||
app.FaucetKeeper = faucet.NewKeeper(
|
||||
app.cdc, keys[faucet.StoreKey], app.SupplyKeeper,
|
||||
)
|
||||
|
||||
// create evidence keeper with router
|
||||
evidenceKeeper := evidence.NewKeeper(
|
||||
@ -261,7 +254,6 @@ func NewEthermintApp(
|
||||
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
|
||||
faucet.NewAppModule(app.FaucetKeeper),
|
||||
)
|
||||
|
||||
// During begin block slashing happens after distr.BeginBlocker so that
|
||||
@ -281,7 +273,6 @@ func NewEthermintApp(
|
||||
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
|
||||
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
|
||||
evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName,
|
||||
faucet.ModuleName,
|
||||
)
|
||||
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
|
@ -58,7 +58,6 @@ ignore:
|
||||
- "docs"
|
||||
- "*.md"
|
||||
- "cmd"
|
||||
- "x/faucet"
|
||||
- "**/*.pb.go"
|
||||
- "types/*.pb.go"
|
||||
- "tests/*"
|
||||
|
@ -2,67 +2,79 @@
|
||||
order: 5
|
||||
-->
|
||||
|
||||
|
||||
# Joining Chainsafe's Public Testnet
|
||||
|
||||
This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io).
|
||||
|
||||
## Steps:
|
||||
1. Install the Ethermint binaries (ethermintd & ethermint cli):
|
||||
```
|
||||
git clone https://github.com/cosmos/ethermint
|
||||
cd ethermint
|
||||
make install
|
||||
```
|
||||
## Steps
|
||||
|
||||
2. Create an Ethermint account:
|
||||
```
|
||||
ethermintcli keys add <keyname>
|
||||
```
|
||||
1. Install the Ethermint binaries (ethermintd & ethermint cli)
|
||||
|
||||
3. Copy genesis file:
|
||||
Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json
|
||||
```bash
|
||||
git clone https://github.com/cosmos/ethermint
|
||||
cd ethermint
|
||||
make install
|
||||
```
|
||||
|
||||
4. Add peers:
|
||||
Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following;
|
||||
```
|
||||
"7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656"
|
||||
```
|
||||
2. Create an Ethermint account
|
||||
|
||||
5. Validate genesis and start the Ethermint network:
|
||||
```
|
||||
ethermintd validate-genesis
|
||||
```
|
||||
```
|
||||
ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace
|
||||
```
|
||||
(we recommend running the command in the background for convenience)
|
||||
```bash
|
||||
ethermintcli keys add <keyname>
|
||||
```
|
||||
|
||||
6. Start the RPC server:
|
||||
```
|
||||
ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace
|
||||
```
|
||||
where `$KEY` is the key name that was used in step 2.
|
||||
(we recommend running the command in the background for convenience)
|
||||
3. Copy genesis file
|
||||
|
||||
7. Request funds from the faucet:
|
||||
You will need to know the Ethereum hex address, and it can be found with the following command:
|
||||
Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json
|
||||
|
||||
```
|
||||
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545
|
||||
```
|
||||
Using the output of the above command, you will then send the command with your valid Ethereum address:
|
||||
```
|
||||
curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000
|
||||
```
|
||||
4. Add peers
|
||||
|
||||
Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following
|
||||
|
||||
```toml
|
||||
"7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656"
|
||||
```
|
||||
|
||||
5. Validate genesis and start the Ethermint network
|
||||
|
||||
```bash
|
||||
ethermintd validate-genesis
|
||||
|
||||
ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace
|
||||
```
|
||||
|
||||
(we recommend running the command in the background for convenience)
|
||||
|
||||
6. Start the RPC server
|
||||
|
||||
```bash
|
||||
ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace
|
||||
```
|
||||
|
||||
where `$KEY` is the key name that was used in step 2.
|
||||
(we recommend running the command in the background for convenience)
|
||||
|
||||
7. Request funds from the faucet
|
||||
|
||||
You will need to know the Ethereum hex address, and it can be found with the following command:
|
||||
|
||||
```bash
|
||||
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545
|
||||
```
|
||||
|
||||
Using the output of the above command, you will then send the command with your valid Ethereum address
|
||||
|
||||
```bash
|
||||
curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000
|
||||
```
|
||||
|
||||
## Public Testnet Node RPC Endpoints
|
||||
|
||||
Node0: `54.210.246.165:8545`
|
||||
Node1: `3.86.104.251:8545`
|
||||
Node2: `18.204.206.179:8545`
|
||||
- **Node0**: `54.210.246.165:8545`
|
||||
- **Node1**: `3.86.104.251:8545`
|
||||
- **Node2**: `18.204.206.179:8545`
|
||||
|
||||
example:
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -H "Content-Type: application/json" 54.210.246.165:8545
|
||||
```
|
@ -12,7 +12,7 @@ Run a local node and start the REST and JSON-RPC clients {synopsis}
|
||||
|
||||
## Automated deployment
|
||||
|
||||
Run the local node with faucet enabled:
|
||||
Run the local node
|
||||
|
||||
::: warning
|
||||
The script below will remove any pre-existing binaries installed. Use the manual deploy if you want
|
||||
|
@ -311,31 +311,6 @@ For more information on seeds and peers, you can the Tendermint [P2P documentati
|
||||
|
||||
The final step is to [start the nodes](./run_node.md#start-node). Once enough voting power (+2/3) from the genesis validators is up-and-running, the testnet will start producing blocks.
|
||||
|
||||
## Testnet faucet
|
||||
|
||||
Once the ethermint daemon is up and running, you can request tokens to your address using the `faucet` module:
|
||||
|
||||
```bash
|
||||
# query your initial balance
|
||||
ethermintcli q bank balances $(ethermintcli keys show <mykey> -a)
|
||||
|
||||
# send a tx to request tokens to your account address
|
||||
ethermintcli tx faucet request 100aphoton --from <mykey>
|
||||
|
||||
# query your balance after the request
|
||||
ethermintcli q bank balances $(ethermintcli keys show <mykey> -a)
|
||||
```
|
||||
|
||||
You can also check to total amount funded by the faucet and the total supply of the chain via:
|
||||
|
||||
```bash
|
||||
# total amount funded by the faucet
|
||||
ethermintcli q faucet funded
|
||||
|
||||
# total supply
|
||||
ethermintcli q supply total
|
||||
```
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about how to setup a [validator](./validator-setup.md) node on Ethermint {hide}
|
||||
|
8
init.sh
8
init.sh
@ -29,9 +29,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
# Enable faucet
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
# increase block time (?)
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="30000"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
@ -56,11 +53,6 @@ ethermintd gentx --name $KEY --amount=1000000000000000000aphoton --keyring-backe
|
||||
# Collect genesis tx
|
||||
ethermintd collect-gentxs
|
||||
|
||||
echo -e '\n\ntestnet faucet enabled'
|
||||
echo -e 'to transfer tokens to your account address use:'
|
||||
echo -e "ethermintcli tx faucet request 100aphoton --from $KEY\n"
|
||||
|
||||
|
||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||
ethermintd validate-genesis
|
||||
|
||||
|
@ -31,9 +31,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
# Enable faucet
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
# Allocate genesis accounts (cosmos formatted addresses)
|
||||
$PWD/build/ethermintd add-genesis-account "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a)" 100000000000000000000aphoton
|
||||
|
||||
@ -51,7 +48,7 @@ $PWD/build/ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:inf
|
||||
|
||||
sleep 1
|
||||
|
||||
# Start the rest server with unlocked faucet key in background and log to file
|
||||
# Start the rest server with unlocked key in background and log to file
|
||||
$PWD/build/ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id $CHAINID --trace > ethermintcli.log &
|
||||
|
||||
solcjs --abi $PWD/tests-solidity/suites/basic/contracts/Counter.sol --bin -o $PWD/tests-solidity/suites/basic/counter
|
||||
|
@ -42,14 +42,6 @@ ethermintd gentx --name $VAL_KEY --keyring-backend test
|
||||
# Collect genesis tx
|
||||
ethermintd collect-gentxs
|
||||
|
||||
# Enable faucet
|
||||
cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json
|
||||
|
||||
echo -e '\n\ntestnet faucet enabled'
|
||||
echo -e 'to transfer tokens to your account address use:'
|
||||
echo -e "ethermintcli tx faucet request 100aphoton --from $VAL_KEY\n"
|
||||
|
||||
|
||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||
ethermintd validate-genesis
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
package faucet
|
||||
|
||||
import (
|
||||
"github.com/cosmos/ethermint/x/faucet/keeper"
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ModuleName = types.ModuleName
|
||||
RouterKey = types.RouterKey
|
||||
StoreKey = types.StoreKey
|
||||
QuerierRoute = types.QuerierRoute
|
||||
)
|
||||
|
||||
var (
|
||||
NewKeeper = keeper.NewKeeper
|
||||
NewQuerier = keeper.NewQuerier
|
||||
ModuleCdc = types.ModuleCdc
|
||||
RegisterCodec = types.RegisterCodec
|
||||
)
|
||||
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
)
|
@ -1,53 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GetQueryCmd defines evm module queries through the cli
|
||||
func GetQueryCmd(cdc *codec.Codec) *cobra.Command {
|
||||
faucetQueryCmd := &cobra.Command{
|
||||
Use: types.ModuleName,
|
||||
Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
faucetQueryCmd.AddCommand(flags.GetCommands(
|
||||
GetCmdFunded(cdc),
|
||||
)...)
|
||||
return faucetQueryCmd
|
||||
}
|
||||
|
||||
// GetCmdFunded queries the total amount funded by the faucet.
|
||||
func GetCmdFunded(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "funded",
|
||||
Short: "Gets storage for an account at a given key",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var out sdk.Coins
|
||||
cdc.MustUnmarshalJSON(res, &out)
|
||||
clientCtx = clientCtx.WithHeight(height)
|
||||
return clientCtx.PrintOutput(out)
|
||||
},
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
// GetTxCmd return faucet sub-command for tx
|
||||
func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
faucetTxCmd := &cobra.Command{
|
||||
Use: types.ModuleName,
|
||||
Short: "faucet transaction subcommands",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
faucetTxCmd.AddCommand(flags.PostCommands(
|
||||
GetCmdRequest(cdc),
|
||||
)...)
|
||||
|
||||
return faucetTxCmd
|
||||
}
|
||||
|
||||
// GetCmdRequest is the CLI command to fund an address with the requested coins
|
||||
func GetCmdRequest(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "request [amount] [other-recipient (optional)]",
|
||||
Short: "request an address with the requested coins",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
clientCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
|
||||
|
||||
amount, err := sdk.ParseCoins(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var recipient sdk.AccAddress
|
||||
if len(args) == 1 {
|
||||
recipient = clientCtx.GetFromAddress()
|
||||
} else {
|
||||
recipient, err = sdk.AccAddressFromBech32(args[1])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.NewMsgFund(amount, clientCtx.GetFromAddress(), recipient)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
// RegisterRoutes register REST endpoints for the faucet module
|
||||
func RegisterRoutes(clientCtx context.CLIContext, r *mux.Router) {
|
||||
r.HandleFunc(fmt.Sprintf("/%s/request", types.ModuleName), requestHandler(clientCtx)).Methods("POST")
|
||||
r.HandleFunc(fmt.Sprintf("/%s/funded", types.ModuleName), fundedHandlerFn(clientCtx)).Methods("GET")
|
||||
}
|
||||
|
||||
// PostRequestBody defines fund request's body.
|
||||
type PostRequestBody struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
Recipient string `json:"receipient" yaml:"receipient"`
|
||||
}
|
||||
|
||||
func requestHandler(clientCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req PostRequestBody
|
||||
if !rest.ReadRESTReq(w, r, clientCtx.Codec, &req) {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request")
|
||||
return
|
||||
}
|
||||
|
||||
baseReq := req.BaseReq.Sanitize()
|
||||
if !baseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
sender, err := sdk.AccAddressFromBech32(baseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var recipient sdk.AccAddress
|
||||
if req.Recipient == "" {
|
||||
recipient = sender
|
||||
} else {
|
||||
recipient, err = sdk.AccAddressFromBech32(req.Recipient)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
msg := types.NewMsgFund(req.Amount, sender, recipient)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
authclient.WriteGenerateStdTxResponse(w, clientCtx, baseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
func fundedHandlerFn(clientCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, _ *http.Request) {
|
||||
res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded))
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
clientCtx = clientCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, clientCtx, res)
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package faucet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// InitGenesis initializes genesis state based on exported genesis
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data types.GenesisState) []abci.ValidatorUpdate {
|
||||
if acc := k.GetFaucetAccount(ctx); acc == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", ModuleName))
|
||||
}
|
||||
|
||||
k.SetEnabled(ctx, data.EnableFaucet)
|
||||
k.SetTimout(ctx, data.Timeout)
|
||||
k.SetCap(ctx, data.FaucetCap)
|
||||
k.SetMaxPerRequest(ctx, data.MaxAmountPerRequest)
|
||||
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
// ExportGenesis exports genesis state
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) types.GenesisState {
|
||||
return types.GenesisState{
|
||||
EnableFaucet: k.IsEnabled(ctx),
|
||||
Timeout: k.GetTimeout(ctx),
|
||||
FaucetCap: k.GetCap(ctx),
|
||||
MaxAmountPerRequest: k.GetMaxPerRequest(ctx),
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package faucet
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
// NewHandler returns a handler for faucet messages.
|
||||
func NewHandler(keeper Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||
switch msg := msg.(type) {
|
||||
case types.MsgFund:
|
||||
return handleMsgFund(ctx, keeper, msg)
|
||||
default:
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleMsgFund handles a message to fund an address
|
||||
func handleMsgFund(ctx sdk.Context, keeper Keeper, msg types.MsgFund) (*sdk.Result, error) {
|
||||
err := keeper.Fund(ctx, msg.Amount, msg.Recipient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
sdk.EventTypeMessage,
|
||||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
|
||||
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()),
|
||||
sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()),
|
||||
sdk.NewAttribute(types.AttributeRecipient, msg.Recipient.String()),
|
||||
),
|
||||
)
|
||||
|
||||
return &sdk.Result{
|
||||
Events: ctx.EventManager().Events(),
|
||||
}, nil
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
// Keeper defines the faucet Keeper.
|
||||
type Keeper struct {
|
||||
cdc *codec.Codec
|
||||
storeKey sdk.StoreKey
|
||||
supplyKeeper types.SupplyKeeper
|
||||
|
||||
// History of users and their funding timeouts. They are reset if the app is reinitialized.
|
||||
timeouts map[string]time.Time
|
||||
}
|
||||
|
||||
// NewKeeper creates a new faucet Keeper instance.
|
||||
func NewKeeper(
|
||||
cdc *codec.Codec, storeKey sdk.StoreKey, supplyKeeper types.SupplyKeeper,
|
||||
) Keeper {
|
||||
return Keeper{
|
||||
cdc: cdc,
|
||||
storeKey: storeKey,
|
||||
supplyKeeper: supplyKeeper,
|
||||
timeouts: make(map[string]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
|
||||
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
||||
}
|
||||
|
||||
// GetFaucetAccount returns the faucet ModuleAccount
|
||||
func (k Keeper) GetFaucetAccount(ctx sdk.Context) supplyexported.ModuleAccountI {
|
||||
return k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName)
|
||||
}
|
||||
|
||||
// Fund checks for timeout and max thresholds and then mints coins and transfers
|
||||
// coins to the recipient.
|
||||
func (k Keeper) Fund(ctx sdk.Context, amount sdk.Coins, recipient sdk.AccAddress) error {
|
||||
if !k.IsEnabled(ctx) {
|
||||
return errors.New("faucet is not enabled. Restart the application and set faucet's 'enable_faucet' genesis field to true")
|
||||
}
|
||||
|
||||
if err := k.rateLimit(ctx, recipient.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
totalRequested := sdk.ZeroInt()
|
||||
for _, coin := range amount {
|
||||
totalRequested = totalRequested.Add(coin.Amount)
|
||||
}
|
||||
|
||||
maxPerReq := k.GetMaxPerRequest(ctx)
|
||||
if totalRequested.GT(maxPerReq) {
|
||||
return fmt.Errorf("canot fund more than %s per request. requested %s", maxPerReq, totalRequested)
|
||||
}
|
||||
|
||||
funded := k.GetFunded(ctx)
|
||||
totalFunded := sdk.ZeroInt()
|
||||
for _, coin := range funded {
|
||||
totalFunded = totalFunded.Add(coin.Amount)
|
||||
}
|
||||
|
||||
cap := k.GetCap(ctx)
|
||||
|
||||
if totalFunded.Add(totalRequested).GT(cap) {
|
||||
return fmt.Errorf("maximum cap of %s reached. Cannot continue funding", cap)
|
||||
}
|
||||
|
||||
if err := k.supplyKeeper.MintCoins(ctx, types.ModuleName, amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.SetFunded(ctx, funded.Add(amount...))
|
||||
|
||||
k.Logger(ctx).Info(fmt.Sprintf("funded %s to %s", amount, recipient))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k Keeper) GetTimeout(ctx sdk.Context) time.Duration {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.TimeoutKey)
|
||||
if len(bz) == 0 {
|
||||
return time.Duration(0)
|
||||
}
|
||||
|
||||
var timeout time.Duration
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &timeout)
|
||||
|
||||
return timeout
|
||||
}
|
||||
|
||||
func (k Keeper) SetTimout(ctx sdk.Context, timeout time.Duration) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinaryBare(timeout)
|
||||
store.Set(types.TimeoutKey, bz)
|
||||
}
|
||||
|
||||
func (k Keeper) IsEnabled(ctx sdk.Context) bool {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.EnableFaucetKey)
|
||||
if len(bz) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var enabled bool
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &enabled)
|
||||
return enabled
|
||||
}
|
||||
|
||||
func (k Keeper) SetEnabled(ctx sdk.Context, enabled bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinaryBare(enabled)
|
||||
store.Set(types.EnableFaucetKey, bz)
|
||||
}
|
||||
|
||||
func (k Keeper) GetCap(ctx sdk.Context) sdk.Int {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.CapKey)
|
||||
if len(bz) == 0 {
|
||||
return sdk.ZeroInt()
|
||||
}
|
||||
|
||||
var cap sdk.Int
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &cap)
|
||||
|
||||
return cap
|
||||
}
|
||||
|
||||
func (k Keeper) SetCap(ctx sdk.Context, cap sdk.Int) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinaryBare(cap)
|
||||
store.Set(types.CapKey, bz)
|
||||
}
|
||||
|
||||
func (k Keeper) GetMaxPerRequest(ctx sdk.Context) sdk.Int {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.MaxPerRequestKey)
|
||||
if len(bz) == 0 {
|
||||
return sdk.ZeroInt()
|
||||
}
|
||||
|
||||
var maxPerReq sdk.Int
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &maxPerReq)
|
||||
|
||||
return maxPerReq
|
||||
}
|
||||
|
||||
func (k Keeper) SetMaxPerRequest(ctx sdk.Context, maxPerReq sdk.Int) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinaryBare(maxPerReq)
|
||||
store.Set(types.MaxPerRequestKey, bz)
|
||||
}
|
||||
|
||||
func (k Keeper) GetFunded(ctx sdk.Context) sdk.Coins {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.FundedKey)
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var funded sdk.Coins
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &funded)
|
||||
|
||||
return funded
|
||||
}
|
||||
|
||||
func (k Keeper) SetFunded(ctx sdk.Context, funded sdk.Coins) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinaryBare(funded)
|
||||
store.Set(types.FundedKey, bz)
|
||||
}
|
||||
|
||||
func (k Keeper) rateLimit(ctx sdk.Context, address string) error {
|
||||
// first time requester, can send request
|
||||
lastRequest, ok := k.timeouts[address]
|
||||
if !ok {
|
||||
k.timeouts[address] = time.Now().UTC()
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultTimeout := k.GetTimeout(ctx)
|
||||
sinceLastRequest := time.Since(lastRequest)
|
||||
|
||||
if defaultTimeout > sinceLastRequest {
|
||||
wait := defaultTimeout - sinceLastRequest
|
||||
return fmt.Errorf("%s has requested funds within the last %s, wait %s before trying again", address, defaultTimeout.String(), wait.String())
|
||||
}
|
||||
|
||||
// user able to send funds since they have waited for period
|
||||
k.timeouts[address] = time.Now().UTC()
|
||||
return nil
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// NewQuerier is the module level router for state queries
|
||||
func NewQuerier(k Keeper) sdk.Querier {
|
||||
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) {
|
||||
switch path[0] {
|
||||
case types.QueryFunded:
|
||||
return queryFunded(ctx, req, k)
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query endpoint")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func queryFunded(ctx sdk.Context, _ abci.RequestQuery, k Keeper) ([]byte, error) {
|
||||
funded := k.GetFunded(ctx)
|
||||
|
||||
bz, err := codec.MarshalJSONIndent(k.cdc, funded)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package faucet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
|
||||
"github.com/cosmos/ethermint/x/faucet/client/cli"
|
||||
"github.com/cosmos/ethermint/x/faucet/client/rest"
|
||||
"github.com/cosmos/ethermint/x/faucet/types"
|
||||
)
|
||||
|
||||
// type check to ensure the interface is properly implemented
|
||||
var (
|
||||
_ module.AppModule = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
)
|
||||
|
||||
// AppModuleBasic defines the basic application module used by the faucet module.
|
||||
type AppModuleBasic struct{}
|
||||
|
||||
// Name returns the faucet module's name.
|
||||
func (AppModuleBasic) Name() string {
|
||||
return types.ModuleName
|
||||
}
|
||||
|
||||
// RegisterCodec registers the faucet module's types for the given codec.
|
||||
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
|
||||
RegisterCodec(cdc)
|
||||
}
|
||||
|
||||
// DefaultGenesis returns default genesis state as raw bytes for the faucet
|
||||
// module.
|
||||
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
|
||||
return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState())
|
||||
}
|
||||
|
||||
// ValidateGenesis performs genesis state validation for the faucet module.
|
||||
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
|
||||
var genesisState types.GenesisState
|
||||
if err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
|
||||
}
|
||||
|
||||
return genesisState.Validate()
|
||||
}
|
||||
|
||||
// RegisterRESTRoutes registers the REST routes for the faucet module.
|
||||
func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) {
|
||||
rest.RegisterRoutes(ctx, rtr)
|
||||
}
|
||||
|
||||
// GetTxCmd returns the root tx command for the faucet module.
|
||||
func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
return cli.GetTxCmd(cdc)
|
||||
}
|
||||
|
||||
// GetQueryCmd returns no root query command for the faucet module.
|
||||
func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
|
||||
return cli.GetQueryCmd(cdc)
|
||||
}
|
||||
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
keeper Keeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule Object
|
||||
func NewAppModule(k Keeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: k,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the faucet module's name.
|
||||
func (AppModule) Name() string {
|
||||
return ModuleName
|
||||
}
|
||||
|
||||
// RegisterInvariants registers the faucet module invariants.
|
||||
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
|
||||
|
||||
// Route returns the message routing key for the faucet module.
|
||||
func (AppModule) Route() string {
|
||||
return RouterKey
|
||||
}
|
||||
|
||||
// NewHandler returns an sdk.Handler for the faucet module.
|
||||
func (am AppModule) NewHandler() sdk.Handler {
|
||||
return NewHandler(am.keeper)
|
||||
}
|
||||
|
||||
// QuerierRoute returns the faucet module's querier route name.
|
||||
func (AppModule) QuerierRoute() string {
|
||||
return QuerierRoute
|
||||
}
|
||||
|
||||
// NewQuerierHandler returns the faucet module sdk.Querier.
|
||||
func (am AppModule) NewQuerierHandler() sdk.Querier {
|
||||
return NewQuerier(am.keeper)
|
||||
}
|
||||
|
||||
// InitGenesis performs genesis initialization for the faucet module. It returns
|
||||
// no validator updates.
|
||||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState types.GenesisState
|
||||
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, am.keeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
// ExportGenesis returns the exported genesis state as raw bytes for the faucet
|
||||
// module.
|
||||
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
|
||||
gs := ExportGenesis(ctx, am.keeper)
|
||||
return types.ModuleCdc.MustMarshalJSON(gs)
|
||||
}
|
||||
|
||||
// BeginBlock returns the begin blocker for the faucet module.
|
||||
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
|
||||
}
|
||||
|
||||
// EndBlock returns the end blocker for the faucet module. It returns no validator
|
||||
// updates.
|
||||
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
// ModuleCdc is the codec for the module
|
||||
var ModuleCdc = codec.New()
|
||||
|
||||
func init() {
|
||||
RegisterCodec(ModuleCdc)
|
||||
}
|
||||
|
||||
// RegisterCodec registers concrete types on the Amino codec
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterConcrete(MsgFund{}, "ethermint/MsgFund", nil)
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWithdrawTooOften withdraw too often
|
||||
ErrWithdrawTooOften = sdkerrors.Register(ModuleName, 2, "each address can withdraw only once")
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
package types
|
||||
|
||||
// Faucet module events
|
||||
const (
|
||||
AttributeRecipient string = "recipient"
|
||||
)
|
||||
|
||||
// Supported endpoints
|
||||
const (
|
||||
QueryFunded = "funded"
|
||||
)
|
@ -1,20 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// SupplyKeeper is required for mining coin
|
||||
type SupplyKeeper interface {
|
||||
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
|
||||
SendCoinsFromModuleToAccount(
|
||||
ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins,
|
||||
) error
|
||||
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI
|
||||
}
|
||||
|
||||
// StakingKeeper is required for getting Denom
|
||||
type StakingKeeper interface {
|
||||
BondDenom(ctx sdk.Context) string
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisState defines the application's genesis state. It contains all the
|
||||
// information required and accounts to initialize the blockchain.
|
||||
type GenesisState struct {
|
||||
// enable faucet funding
|
||||
EnableFaucet bool `json:"enable_faucet" yaml:"enable_faucet"`
|
||||
// addresses can send requests every <Timeout> duration
|
||||
Timeout time.Duration `json:"timeout" yaml:"timeout"`
|
||||
// max total amount to be funded by the faucet
|
||||
FaucetCap sdk.Int `json:"faucet_cap" yaml:"faucet_cap"`
|
||||
// max amount per request (i.e sum of all requested coin amounts).
|
||||
MaxAmountPerRequest sdk.Int `json:"max_amount_per_request" yaml:"max_amount_per_request"`
|
||||
}
|
||||
|
||||
// Validate performs a basic validation of the GenesisState fields.
|
||||
func (gs GenesisState) Validate() error {
|
||||
if gs.Timeout < 0 {
|
||||
return fmt.Errorf("timeout cannot be negative: %s", gs.Timeout)
|
||||
}
|
||||
if gs.FaucetCap.IsNegative() {
|
||||
return fmt.Errorf("faucet cap cannot be negative: %d", gs.FaucetCap)
|
||||
}
|
||||
if gs.MaxAmountPerRequest.IsNegative() {
|
||||
return fmt.Errorf("max amount per request cannot be negative: %d", gs.MaxAmountPerRequest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultGenesisState sets default evm genesis config
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
EnableFaucet: false,
|
||||
Timeout: 20 * time.Minute,
|
||||
FaucetCap: sdk.NewInt(1000000000),
|
||||
MaxAmountPerRequest: sdk.NewInt(1000),
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package types
|
||||
|
||||
const (
|
||||
// ModuleName is the name of the module
|
||||
ModuleName = "faucet"
|
||||
|
||||
// StoreKey to be used when creating the KVStore
|
||||
StoreKey = ModuleName
|
||||
|
||||
// RouterKey uses module name for tx routing
|
||||
RouterKey = ModuleName
|
||||
|
||||
// QuerierRoute uses module name for query routing
|
||||
QuerierRoute = ModuleName
|
||||
)
|
||||
|
||||
var (
|
||||
EnableFaucetKey = []byte{0x01}
|
||||
TimeoutKey = []byte{0x02}
|
||||
CapKey = []byte{0x03}
|
||||
MaxPerRequestKey = []byte{0x04}
|
||||
FundedKey = []byte{0x05}
|
||||
)
|
@ -1,52 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// MsgFund funds a recipient address
|
||||
type MsgFund struct {
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Recipient sdk.AccAddress `json:"receipient" yaml:"receipient"`
|
||||
}
|
||||
|
||||
// NewMsgFund is a constructor function for NewMsgFund
|
||||
func NewMsgFund(amount sdk.Coins, sender, recipient sdk.AccAddress) MsgFund {
|
||||
return MsgFund{
|
||||
Amount: amount,
|
||||
Sender: sender,
|
||||
Recipient: recipient,
|
||||
}
|
||||
}
|
||||
|
||||
// Route should return the name of the module
|
||||
func (msg MsgFund) Route() string { return RouterKey }
|
||||
|
||||
// Type should return the action
|
||||
func (msg MsgFund) Type() string { return "fund" }
|
||||
|
||||
// ValidateBasic runs stateless checks on the message
|
||||
func (msg MsgFund) ValidateBasic() error {
|
||||
if !msg.Amount.IsValid() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
|
||||
}
|
||||
if msg.Sender.Empty() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "sender %s", msg.Sender.String())
|
||||
}
|
||||
if msg.Recipient.Empty() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "recipient %s", msg.Recipient.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignBytes encodes the message for signing
|
||||
func (msg MsgFund) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
|
||||
}
|
||||
|
||||
// GetSigners defines whose signature is required
|
||||
func (msg MsgFund) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Sender}
|
||||
}
|
Loading…
Reference in New Issue
Block a user