diff --git a/sample_pool.json b/sample_pool.json index ea20e31c..3a63999a 100644 --- a/sample_pool.json +++ b/sample_pool.json @@ -1,6 +1,6 @@ { "weights": "1ibc/9117A26BA81E29FA4F78F57DC2BD90CD3D26848101BA880445F119B22A1E254E,1ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878", - "initial-deposit": "500000000000ibc/9117A26BA81E29FA4F78F57DC2BD90CD3D26848101BA880445F119B22A1E254E,1000000000000ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878", + "initial-deposit": "500000000000ibc/9117A26BA81E29FA4F78F57DC2BD90CD3D26848101BA880445F119B22A1E254E,100000000000ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878", "swap-fee": "0.01", "exit-fee": "0", "future-governor": "168h" diff --git a/scripts/README.md b/scripts/README.md index 7e3c2348..17628733 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -2,58 +2,106 @@ ## Setup -``` # Deploy chains +Run Feeabs node +``` ./scripts/node_start/runnode_custom.sh c -./scripts/node_start/runnode_osmosis.sh +``` +Run Osmosis node +``` +./scripts/node_start/runnode_osmosis.sh c +``` +Run Gaia node +``` +./scripts/node_start/runnode_gaia.sh c +``` # Run relayer -./scripts/run_relayer.sh -# Create an osmosis pool -./scripts/create_pool.sh -# Deploy contract and create relayer channel -./scripts/deploy_and_channel.sh +Run Feeabs - Osmosis relayer +``` +./scripts/run_relayer_feeabs_osmo.sh +``` +Run Feeabs - Gaia relayer +``` +./scripts/run_relayer_feeabs_gaia.sh +``` +Run Osmosis - Gaia relayer +``` +./scripts/run_relayer_osmo_gaia.sh +``` +# Setup IBC channel +Run the following command to setup IBC channel +``` +hermes --config scripts/relayer_hermes/config_feeabs_osmosis.toml create channel --a-chain testing --b-chain feeappd-t1 --a-port transfer --b-port transfer --new-client-connection --yes +hermes --config scripts/relayer_hermes/config_feeabs_osmosis.toml create channel --a-chain testing --b-chain feeappd-t1 --a-port icqhost --b-port feeabs --new-client-connection --yes +hermes --config scripts/relayer_hermes/config_feeabs_gaia.toml create channel --a-chain gaiad-t1 --b-chain feeappd-t1 --a-port transfer --b-port transfer --new-client-connection --yes +hermes --config scripts/relayer_hermes/config_osmosis_gaia.toml create channel --a-chain gaiad-t1 --b-chain testing --a-port transfer --b-port transfer --new-client-connection --yes ``` -## Test +After running, the channel map should like this +``` +feeabs - osmo: channel-0 channel-0 +feeabs - osmo: (feeabs - icqhost) channel-1 channel-1 +feeabs - gaia: channel-2 channel-0 +osmo - gaia: channel-2 channel-1 +``` +# Create an osmosis pool +Get Osmosis testing address ``` -feeappd tx feeabs queryomosis --from feeacc --keyring-backend test --chain-id feeappd-t1 --yes -# Wait for about 10 sec -feeappd q feeabs osmo-spot-price +export VALIDATOR=$(osmosisd keys show validator1 -a --keyring-backend test) +export OWNER=$(osmosisd keys show deployer -a --keyring-backend test) ``` -The result looks like this +Transfer token from Feeabs and Gaia to Osmosis +``` +feeappd tx ibc-transfer transfer transfer channel-0 "$VALIDATOR" 1000000000000stake --from feeacc --keyring-backend test --chain-id feeappd-t1 --yes --fees 5000stake +gaiad tx ibc-transfer transfer transfer channel-1 "$VALIDATOR" 1000000000000uatom --from gnad --keyring-backend test --chain-id gaiad-t1 --yes --fees 5000stake +``` +Create pool ``` -base_asset: osmo -quote_asset: stake -spot_price: "2.000000000000000000" +cat > sample_pool.json < 0 { + return next(ctx, tx, simulate) + } + // After all the checks, the tx is confirmed: + // feeCoins denoms subset off feeRequired (or replaced with fee-abstraction) + // Not bypass + // feeCoins != [] + // Not contain zeroCoinFeesDenomReq's denoms + // + // check if the feeCoins has coins' amount higher/equal to nonZeroCoinFeesReq + if !feeCoins.IsAnyGTE(nonZeroCoinFeesReq) { + err := sdkerrors.Wrapf(errorstypes.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, feeRequired) + if byPassExceedMaxGasUsage { + err = sdkerrors.Wrapf(errorstypes.ErrInsufficientFee, "Insufficient fees; bypass-min-fee-msg-types with gas consumption exceeds the maximum allowed gas value.") + } + return ctx, err + } } return next(ctx, tx, simulate) } + +func (famfd FeeAbstrationMempoolFeeDecorator) DefaultZeroFee(ctx sdk.Context) ([]sdk.DecCoin, error) { + bondDenom := famfd.feeabsKeeper.GetDefaultBondDenom(ctx) + if bondDenom == "" { + return nil, errors.New("empty staking bond denomination") + } + + return []sdk.DecCoin{sdk.NewDecCoinFromDec(bondDenom, sdk.NewDec(0))}, nil +} + +// GetTxFeeRequired returns the required fees for the given FeeTx. +func (famfd FeeAbstrationMempoolFeeDecorator) GetTxFeeRequired(ctx sdk.Context, gasLimit int64) (sdk.Coins, error) { + var ( + minGasPrices sdk.DecCoins + err error + ) + + minGasPrices = ctx.MinGasPrices() + // if min_gas_prices is empty set, set to 0(bond_denom) + if len(minGasPrices) == 0 { + minGasPrices, err = famfd.DefaultZeroFee(ctx) + if err != nil { + return sdk.Coins{}, err + } + } + + requiredFees := make(sdk.Coins, len(minGasPrices)) + // Determine the required fees by multiplying each required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdk.NewDec(gasLimit) + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(glDec) + requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + return requiredFees.Sort(), nil +} diff --git a/x/feeabs/ante/fee_utils.go b/x/feeabs/ante/fee_utils.go new file mode 100644 index 00000000..40f13534 --- /dev/null +++ b/x/feeabs/ante/fee_utils.go @@ -0,0 +1,40 @@ +// Reference: https://github.com/cosmos/gaia/blob/main/x/globalfee/ante/fee_utils.go +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// splitCoinsByDenoms returns the given coins split in two whether +// their demon is or isn't found in the given denom map. +func splitCoinsByDenoms(feeCoins sdk.Coins, denomMap map[string]struct{}) (sdk.Coins, sdk.Coins) { + feeCoinsNonZeroDenom, feeCoinsZeroDenom := sdk.Coins{}, sdk.Coins{} + + for _, fc := range feeCoins { + _, found := denomMap[fc.Denom] + if found { + feeCoinsZeroDenom = append(feeCoinsZeroDenom, fc) + } else { + feeCoinsNonZeroDenom = append(feeCoinsNonZeroDenom, fc) + } + } + + return feeCoinsNonZeroDenom.Sort(), feeCoinsZeroDenom.Sort() +} + +// getNonZeroFees returns the given fees nonzero coins +// and a map storing the zero coins's denoms +func getNonZeroFees(fees sdk.Coins) (sdk.Coins, map[string]struct{}) { + requiredFeesNonZero := sdk.Coins{} + requiredFeesZeroDenom := map[string]struct{}{} + + for _, gf := range fees { + if gf.IsZero() { + requiredFeesZeroDenom[gf.Denom] = struct{}{} + } else { + requiredFeesNonZero = append(requiredFeesNonZero, gf) + } + } + + return requiredFeesNonZero.Sort(), requiredFeesZeroDenom +} diff --git a/x/feeabs/keeper/keeper.go b/x/feeabs/keeper/keeper.go index fd74c1ac..eebe9a5f 100644 --- a/x/feeabs/keeper/keeper.go +++ b/x/feeabs/keeper/keeper.go @@ -72,6 +72,10 @@ func (k Keeper) GetFeeAbsModuleAddress() sdk.AccAddress { return k.ak.GetModuleAddress(types.ModuleName) } +func (k Keeper) GetDefaultBondDenom(ctx sdk.Context) string { + return k.sk.BondDenom(ctx) +} + // need to implement func (k Keeper) CalculateNativeFromIBCCoins(ctx sdk.Context, ibcCoins sdk.Coins, chainConfig types.HostChainFeeAbsConfig) (coins sdk.Coins, err error) { err = k.verifyIBCCoins(ctx, ibcCoins) diff --git a/x/feeabs/types/keys.go b/x/feeabs/types/keys.go index 8300b29d..ecbb7659 100644 --- a/x/feeabs/types/keys.go +++ b/x/feeabs/types/keys.go @@ -20,6 +20,12 @@ const ( KeySeparator = "|" ) +type ( + ByPassMsgKey struct{} + ByPassExceedMaxGasUsageKey struct{} + GlobalFeeKey struct{} +) + var ( OsmosisTwapExchangeRate = []byte{0x01} // Key for the exchange rate of osmosis (to native token) KeyChannelID = []byte{0x02} // Key for IBC channel to osmosis