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
|
### 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.
|
* (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
|
### 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
|
## [v0.4.0] - 2020-12-15
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
ethermintcodec "github.com/cosmos/ethermint/codec"
|
ethermintcodec "github.com/cosmos/ethermint/codec"
|
||||||
ethermint "github.com/cosmos/ethermint/types"
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
"github.com/cosmos/ethermint/x/evm"
|
"github.com/cosmos/ethermint/x/evm"
|
||||||
"github.com/cosmos/ethermint/x/faucet"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
@ -74,7 +73,6 @@ var (
|
|||||||
evidence.AppModuleBasic{},
|
evidence.AppModuleBasic{},
|
||||||
upgrade.AppModuleBasic{},
|
upgrade.AppModuleBasic{},
|
||||||
evm.AppModuleBasic{},
|
evm.AppModuleBasic{},
|
||||||
faucet.AppModuleBasic{},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// module account permissions
|
// module account permissions
|
||||||
@ -85,7 +83,6 @@ var (
|
|||||||
staking.BondedPoolName: {supply.Burner, supply.Staking},
|
staking.BondedPoolName: {supply.Burner, supply.Staking},
|
||||||
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
|
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
|
||||||
gov.ModuleName: {supply.Burner},
|
gov.ModuleName: {supply.Burner},
|
||||||
faucet.ModuleName: {supply.Minter},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// module accounts that are allowed to receive tokens
|
// module accounts that are allowed to receive tokens
|
||||||
@ -126,7 +123,6 @@ type EthermintApp struct {
|
|||||||
ParamsKeeper params.Keeper
|
ParamsKeeper params.Keeper
|
||||||
EvidenceKeeper evidence.Keeper
|
EvidenceKeeper evidence.Keeper
|
||||||
EvmKeeper *evm.Keeper
|
EvmKeeper *evm.Keeper
|
||||||
FaucetKeeper faucet.Keeper
|
|
||||||
|
|
||||||
// the module manager
|
// the module manager
|
||||||
mm *module.Manager
|
mm *module.Manager
|
||||||
@ -157,7 +153,7 @@ func NewEthermintApp(
|
|||||||
bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
||||||
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
||||||
gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey,
|
gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey,
|
||||||
evm.StoreKey, faucet.StoreKey,
|
evm.StoreKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
|
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
|
||||||
@ -215,9 +211,6 @@ func NewEthermintApp(
|
|||||||
app.EvmKeeper = evm.NewKeeper(
|
app.EvmKeeper = evm.NewKeeper(
|
||||||
app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper,
|
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
|
// create evidence keeper with router
|
||||||
evidenceKeeper := evidence.NewKeeper(
|
evidenceKeeper := evidence.NewKeeper(
|
||||||
@ -261,7 +254,6 @@ func NewEthermintApp(
|
|||||||
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper),
|
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper),
|
||||||
evidence.NewAppModule(app.EvidenceKeeper),
|
evidence.NewAppModule(app.EvidenceKeeper),
|
||||||
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
|
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
|
||||||
faucet.NewAppModule(app.FaucetKeeper),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// During begin block slashing happens after distr.BeginBlocker so that
|
// During begin block slashing happens after distr.BeginBlocker so that
|
||||||
@ -281,7 +273,6 @@ func NewEthermintApp(
|
|||||||
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
|
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
|
||||||
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
|
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
|
||||||
evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName,
|
evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName,
|
||||||
faucet.ModuleName,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||||
|
@ -58,7 +58,6 @@ ignore:
|
|||||||
- "docs"
|
- "docs"
|
||||||
- "*.md"
|
- "*.md"
|
||||||
- "cmd"
|
- "cmd"
|
||||||
- "x/faucet"
|
|
||||||
- "**/*.pb.go"
|
- "**/*.pb.go"
|
||||||
- "types/*.pb.go"
|
- "types/*.pb.go"
|
||||||
- "tests/*"
|
- "tests/*"
|
||||||
|
@ -2,67 +2,79 @@
|
|||||||
order: 5
|
order: 5
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
# Joining Chainsafe's Public Testnet
|
# Joining Chainsafe's Public Testnet
|
||||||
|
|
||||||
This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io).
|
This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io).
|
||||||
|
|
||||||
## Steps:
|
## Steps
|
||||||
1. Install the Ethermint binaries (ethermintd & ethermint cli):
|
|
||||||
```
|
|
||||||
git clone https://github.com/cosmos/ethermint
|
|
||||||
cd ethermint
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create an Ethermint account:
|
1. Install the Ethermint binaries (ethermintd & ethermint cli)
|
||||||
```
|
|
||||||
ethermintcli keys add <keyname>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Copy genesis file:
|
```bash
|
||||||
Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json
|
git clone https://github.com/cosmos/ethermint
|
||||||
|
cd ethermint
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
4. Add peers:
|
2. Create an Ethermint account
|
||||||
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"
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Validate genesis and start the Ethermint network:
|
```bash
|
||||||
```
|
ethermintcli keys add <keyname>
|
||||||
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:
|
3. Copy genesis file
|
||||||
```
|
|
||||||
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:
|
Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json
|
||||||
You will need to know the Ethereum hex address, and it can be found with the following command:
|
|
||||||
|
|
||||||
```
|
4. Add peers
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545
|
|
||||||
```
|
Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following
|
||||||
Using the output of the above command, you will then send the command with your valid Ethereum address:
|
|
||||||
```
|
```toml
|
||||||
curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000
|
"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
|
## Public Testnet Node RPC Endpoints
|
||||||
|
|
||||||
Node0: `54.210.246.165:8545`
|
- **Node0**: `54.210.246.165:8545`
|
||||||
Node1: `3.86.104.251:8545`
|
- **Node1**: `3.86.104.251:8545`
|
||||||
Node2: `18.204.206.179:8545`
|
- **Node2**: `18.204.206.179:8545`
|
||||||
|
|
||||||
example:
|
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
|
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
|
## Automated deployment
|
||||||
|
|
||||||
Run the local node with faucet enabled:
|
Run the local node
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
The script below will remove any pre-existing binaries installed. Use the manual deploy if you want
|
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.
|
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}
|
## Next {hide}
|
||||||
|
|
||||||
Learn about how to setup a [validator](./validator-setup.md) node on Ethermint {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["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
|
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 (?)
|
# 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
|
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
|
# Collect genesis tx
|
||||||
ethermintd collect-gentxs
|
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
|
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||||
ethermintd validate-genesis
|
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["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
|
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)
|
# Allocate genesis accounts (cosmos formatted addresses)
|
||||||
$PWD/build/ethermintd add-genesis-account "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a)" 100000000000000000000aphoton
|
$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
|
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 &
|
$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
|
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
|
# Collect genesis tx
|
||||||
ethermintd collect-gentxs
|
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
|
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||||
ethermintd validate-genesis
|
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