Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autopilot enhancement #771

Closed
wants to merge 8 commits into from
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,8 @@ func NewStrideApp(
keys[autopilottypes.StoreKey],
app.GetSubspace(autopilottypes.ModuleName),
app.StakeibcKeeper,
app.ClaimKeeper)
app.ClaimKeeper,
app.TransferKeeper)
autopilotModule := autopilot.NewAppModule(appCodec, app.AutopilotKeeper)

// Register Gov (must be registerd after stakeibc)
Expand Down
21 changes: 15 additions & 6 deletions app/upgrades/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Upgrades

## Create Upgrade Handler

```go
// app/upgrades/{upgradeVersion}/upgrades.go

Expand Down Expand Up @@ -28,6 +29,7 @@ func CreateUpgradeHandler(
```

## Register Upgrade Handler

```go
// app/upgrades.go

Expand Down Expand Up @@ -64,26 +66,31 @@ func (app *StrideApp) setupUpgradeHandlers() {
```

# Migrations (Only required if the state changed)

## Store Old Proto Types

```go
// x/{moduleName}/migrations/{oldVersion}/types/{data_type}.pb.go
```

## Increment the Module's Consensus Version
* The consensus version is different from the chain version - it is specific to each module and is incremented every time state is migrated

- The consensus version is different from the chain version - it is specific to each module and is incremented every time state is migrated

```go
// x/{moduleName}/module.go
func (AppModule) ConsensusVersion() uint64 { return 2 }
```

## Define Migration Logic

```go
// x/{moduleName}/migrations/{new-consensus-version}/migrations.go
package {upgradeVersion}

import (
sdk "github.com/cosmos/cosmos-sdk/types"
{new-consensus-version} "github.com/Stride-Labs/stride/v9/x/records/migrations/{new-consensus-version}"
{new-consensus-version} "github.com/Stride-Labs/stride/v11/x/records/migrations/{new-consensus-version}"
)

// TODO: Add migration logic to deserialize with old protos and re-serialize with new ones
Expand All @@ -94,11 +101,12 @@ func MigrateStore(ctx sdk.Context) error {
```

## Specify the Migration in the Upgrade Handler

```go
// app/upgrades/{upgradeVersion}/upgrades.go

import (
{module}migration "github.com/Stride-Labs/stride/v9/x/{module}/migrations/{new-consensus-version}"
{module}migration "github.com/Stride-Labs/stride/v11/x/{module}/migrations/{new-consensus-version}"
)

// CreateUpgradeHandler creates an SDK upgrade handler for {upgradeVersion}
Expand All @@ -112,16 +120,17 @@ func CreateUpgradeHandler(
if err := {module}migration.MigrateStore(ctx, {module}StoreKey, cdc); err != nil {
return vm, errorsmod.Wrapf(err, "unable to migrate {module} store")
}
vm[{moduleName}] = mm.GetVersionMap()[{moduleName}]
vm[{moduleName}] = mm.GetVersionMap()[{moduleName}]
return mm.RunMigrations(ctx, configurator, vm)
}
}
```

## Add Additional Parameters to `CreateUpgradeHandler` Invocation
## Add Additional Parameters to `CreateUpgradeHandler` Invocation

```go
// app/upgrades.go
...
{upgradeVersion}.CreateUpgradeHandler(app.mm, app.configurator, app.appCodec, app.{module}Keeper),
...
```
```
7 changes: 7 additions & 0 deletions dockernet/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ STSTARS_DENOM="stustars"
STWALK_DENOM="stuwalk"
STEVMOS_DENOM="staevmos"

IBC_GAIA_CHANNEL_0_STATOM_DENOM='ibc/054A44EC8D9B68B9A6F0D5708375E00A5569A28F21E0064FF12CADC3FEF1D04F'
IBC_GAIA_CHANNEL_1_STATOM_DENOM='ibc/8B21DA0E34A49AE151FEEBCCF3AFE1188E24BA8E19439FB93434DF6008E7E228'
IBC_GAIA_CHANNEL_2_STATOM_DENOM='ibc/60CB7A5465C318C8F68F603D78721A2ECC1DA2D0E905C6AD9ACD1CAC3F0DB22D'
IBC_GAIA_CHANNEL_3_STATOM_DENOM='ibc/0C0FD07C29EB075C18EA77B73CF9FCE68A268E0738C9F5B11D13E418AD889437'

IBC_GAIA_STATOM_DENOM=$IBC_GAIA_CHANNEL_0_STATOM_DENOM

IBC_STRD_DENOM='ibc/FF6C2E86490C1C4FBBD24F55032831D2415B9D7882F85C3CC9C2401D79362BEA'

IBC_GAIA_CHANNEL_0_DENOM='ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
Expand Down
84 changes: 84 additions & 0 deletions dockernet/tests/integration_tests.bats
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,55 @@ setup_file() {
assert_equal "$sttoken_balance_diff" "$PACKET_FORWARD_STAKE_AMOUNT"
}

@test "[INTEGRATION-BASIC-$CHAIN_NAME] transfer st$HOST_DENOM to host chain" {
# get initial balances
sttoken_balance_start=$($STRIDE_MAIN_CMD q bank balances $(STRIDE_ADDRESS) --denom st$HOST_DENOM | GETBAL)
stibctoken_balance_start=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)

# do IBC transfer
$STRIDE_MAIN_CMD tx ibc-transfer transfer transfer $STRIDE_TRANFER_CHANNEL $HOST_VAL_ADDRESS ${PACKET_FORWARD_STAKE_AMOUNT}st${HOST_DENOM} --from $STRIDE_VAL -y &
WAIT_FOR_BLOCK $STRIDE_LOGS 8

# make sure stATOM balance decreased
sttoken_balance_end=$($STRIDE_MAIN_CMD q bank balances $(STRIDE_ADDRESS) --denom st$HOST_DENOM | GETBAL)
stibctoken_balance_end=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)
sttoken_balance_diff=$(($sttoken_balance_start-$sttoken_balance_end))
stibctoken_balance_diff=$(($stibctoken_balance_end-$stibctoken_balance_start))
assert_equal "$sttoken_balance_diff" "$PACKET_FORWARD_STAKE_AMOUNT"
assert_equal "$stibctoken_balance_diff" "$PACKET_FORWARD_STAKE_AMOUNT"
}

@test "[INTEGRATION-BASIC-$CHAIN_NAME] packet forwarding automatically liquid stake and ibc transfer stAsset to original network" {
skip "DefaultActive set to false, skip test"
memo='{ "autopilot": { "receiver": "'"$(STRIDE_ADDRESS)"'", "stakeibc": { "action": "LiquidStake", "ibc_receiver": "'$HOST_VAL_ADDRESS'" } } }'

# get initial balances
stibctoken_balance_start=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)

# Send the IBC transfer with the JSON memo
transfer_msg_prefix="$HOST_MAIN_CMD tx ibc-transfer transfer transfer $HOST_TRANSFER_CHANNEL"
if [[ "$CHAIN_NAME" == "GAIA" ]]; then
# For GAIA (ibc-v3), pass the memo into the receiver field
$transfer_msg_prefix "$memo" ${PACKET_FORWARD_STAKE_AMOUNT}${HOST_DENOM} --from $HOST_VAL -y
elif [[ "$CHAIN_NAME" == "HOST" ]]; then
# For HOST (ibc-v5), pass an address for a receiver and the memo in the --memo field
$transfer_msg_prefix $(STRIDE_ADDRESS) ${PACKET_FORWARD_STAKE_AMOUNT}${HOST_DENOM} --memo "$memo" --from $HOST_VAL -y
else
# For all other hosts, skip this test
skip "Packet forward liquid stake test is only run on GAIA and HOST"
fi

# Wait for the transfer to complete
WAIT_FOR_BALANCE_CHANGE $CHAIN_NAME $HOST_VAL_ADDRESS $IBC_GAIA_STATOM_DENOM

# make sure stATOM balance increased
stibctoken_balance_end=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)
stibctoken_balance_diff=$(($stibctoken_balance_end-$stibctoken_balance_start))
assert_equal "$stibctoken_balance_diff" "$PACKET_FORWARD_STAKE_AMOUNT"
}

# TODO: handle IBC transfer to other network case

# check that tokens on the host are staked
@test "[INTEGRATION-BASIC-$CHAIN_NAME] tokens on $CHAIN_NAME were staked" {
# wait for another epoch to pass so that tokens are staked
Expand All @@ -198,6 +247,41 @@ setup_file() {
assert_equal "$stake_diff" "1"
}

@test "[INTEGRATION-BASIC-$CHAIN_NAME] packet forwarding automatically redeem stake" {
skip "DefaultActive set to false, skip test"
# get initial balances
stibctoken_balance_start=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)

memo='{ "autopilot": { "receiver": "'"$(STRIDE_ADDRESS)"'", "stakeibc": { "action": "RedeemStake", "ibc_receiver": "'$HOST_RECEIVER_ADDRESS'" } } }'

# do IBC transfer
transfer_msg_prefix="$HOST_MAIN_CMD tx ibc-transfer transfer transfer $HOST_TRANSFER_CHANNEL"
if [[ "$CHAIN_NAME" == "GAIA" ]]; then
# For GAIA (ibc-v3), pass the memo into the receiver field
$transfer_msg_prefix "$memo" 200${IBC_GAIA_STATOM_DENOM} --from $HOST_VAL -y
elif [[ "$CHAIN_NAME" == "HOST" ]]; then
# For HOST (ibc-v5), pass an address for a receiver and the memo in the --memo field
$transfer_msg_prefix $(STRIDE_ADDRESS)200${IBC_GAIA_STATOM_DENOM} --memo "$memo" --from $HOST_VAL -y
else
# For all other hosts, skip this test
skip "Packet forward liquid stake test is only run on GAIA and HOST"
fi

WAIT_FOR_BALANCE_CHANGE $CHAIN_NAME $HOST_VAL_ADDRESS $IBC_GAIA_STATOM_DENOM

# make sure stATOM balance decreased
stibctoken_balance_end=$($HOST_MAIN_CMD q bank balances $HOST_VAL_ADDRESS --denom $IBC_GAIA_STATOM_DENOM | GETBAL)
stibctoken_balance_diff=$(($stibctoken_balance_start-$stibctoken_balance_end))
assert_equal "$stibctoken_balance_diff" "200"

WAIT_FOR_BLOCK $STRIDE_LOGS 5

# check that the tokens were transferred to the redemption account
AMOUNT=$($STRIDE_MAIN_CMD q records list-user-redemption-record | grep -Fiw 'amount' | head -n 1 | grep -o -E '[0-9]+')
amount_positive=$(($AMOUNT > 0))
assert_equal "$amount_positive" "1"
}

# check that redemptions and claims work
@test "[INTEGRATION-BASIC-$CHAIN_NAME] redemption works" {
# get initial balance of redemption ICA
Expand Down
7 changes: 6 additions & 1 deletion proto/stride/stakeibc/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ message MsgLiquidStake {
string host_denom = 3;
}

message MsgLiquidStakeResponse {}
message MsgLiquidStakeResponse {
string st_asset = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Coin",
(gogoproto.nullable) = false
];
}

message MsgClearBalance {
string creator = 1;
Expand Down
2 changes: 1 addition & 1 deletion x/autopilot/keeper/airdrop.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (k Keeper) TryUpdateAirdropClaim(
if senderStrideAddress == "" {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid sender address (%s)", data.Sender))
}
newStrideAddress := packetMetadata.StrideAddress
newStrideAddress := data.Receiver

// find the airdrop for this host chain ID
airdrop, found := k.claimKeeper.GetAirdropByChainId(ctx, hostZone.ChainId)
Expand Down
4 changes: 2 additions & 2 deletions x/autopilot/keeper/airdrop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func (s *KeeperTestSuite) TestAirdropOnRecvPacket() {
destinationPortID: transfertypes.PortID,
packetData: transfertypes.FungibleTokenPacketData{
Receiver: strideAddress,
Memo: strings.Repeat("X", 300),
Memo: strings.Repeat("X", 600),
},
transferShouldSucceed: false,
airdropShouldUpdate: false,
Expand All @@ -257,7 +257,7 @@ func (s *KeeperTestSuite) TestAirdropOnRecvPacket() {
destinationChannelID: ibctesting.FirstChannelID,
destinationPortID: transfertypes.PortID,
packetData: transfertypes.FungibleTokenPacketData{
Receiver: strings.Repeat("X", 300),
Receiver: strings.Repeat("X", 600),
Memo: "",
},
transferShouldSucceed: false,
Expand Down
4 changes: 4 additions & 0 deletions x/autopilot/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper"

"github.com/Stride-Labs/stride/v11/x/autopilot/types"
claimkeeper "github.com/Stride-Labs/stride/v11/x/claim/keeper"
Expand All @@ -22,6 +23,7 @@ type (
paramstore paramtypes.Subspace
stakeibcKeeper stakeibckeeper.Keeper
claimKeeper claimkeeper.Keeper
transferKeeper ibctransferkeeper.Keeper
}
)

Expand All @@ -31,6 +33,7 @@ func NewKeeper(
ps paramtypes.Subspace,
stakeibcKeeper stakeibckeeper.Keeper,
claimKeeper claimkeeper.Keeper,
transferKeeper ibctransferkeeper.Keeper,
) *Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
Expand All @@ -43,6 +46,7 @@ func NewKeeper(
paramstore: ps,
stakeibcKeeper: stakeibcKeeper,
claimKeeper: claimKeeper,
transferKeeper: transferKeeper,
}
}

Expand Down
54 changes: 46 additions & 8 deletions x/autopilot/keeper/liquidstake.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,16 @@ func (k Keeper) TryLiquidStaking(
}

// Note: newData.denom is base denom e.g. uatom - not ibc/xxx
var token = sdk.NewCoin(newData.Denom, amount)
var token = sdk.Coin{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed afaict

Denom: newData.Denom,
Amount: amount,
}

if err := token.Validate(); err != nil {
return err
}

prefixedDenom := transfertypes.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) + newData.Denom
prefixedDenom := transfertypes.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), newData.Denom)
ibcDenom := transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom()

hostZone, err := k.stakeibcKeeper.GetHostZoneFromHostDenom(ctx, token.Denom)
Expand All @@ -52,15 +59,15 @@ func (k Keeper) TryLiquidStaking(
return fmt.Errorf("ibc denom %s is not equal to host zone ibc denom %s", ibcDenom, hostZone.IbcDenom)
}

strideAddress, err := sdk.AccAddressFromBech32(packetMetadata.StrideAddress)
strideAddress, err := sdk.AccAddressFromBech32(newData.Receiver)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid stride_address (%s) in autopilot memo", strideAddress)
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid receiver (%s) in autopilot memo", strideAddress)
}

return k.RunLiquidStake(ctx, strideAddress, token)
return k.RunLiquidStake(ctx, strideAddress, token, packetMetadata)
}

func (k Keeper) RunLiquidStake(ctx sdk.Context, addr sdk.AccAddress, token sdk.Coin) error {
func (k Keeper) RunLiquidStake(ctx sdk.Context, addr sdk.AccAddress, token sdk.Coin, packetMetadata types.StakeibcPacketMetadata) error {
msg := &stakeibctypes.MsgLiquidStake{
Creator: addr.String(),
Amount: token.Amount,
Expand All @@ -72,12 +79,43 @@ func (k Keeper) RunLiquidStake(ctx sdk.Context, addr sdk.AccAddress, token sdk.C
}

msgServer := stakeibckeeper.NewMsgServerImpl(k.stakeibcKeeper)
_, err := msgServer.LiquidStake(
lsRes, err := msgServer.LiquidStake(
sdk.WrapSDKContext(ctx),
msg,
)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}
return nil
if packetMetadata.IbcReceiver == "" {
return nil
}

hostZone, err := k.stakeibcKeeper.GetHostZoneFromHostDenom(ctx, token.Denom)
if err != nil {
return err
}

return k.IBCTransferStAsset(ctx, lsRes.StAsset, addr.String(), hostZone, packetMetadata)
}

func (k Keeper) IBCTransferStAsset(ctx sdk.Context, stAsset sdk.Coin, sender string, hostZone *stakeibctypes.HostZone, packetMetadata types.StakeibcPacketMetadata) error {
ibcTransferTimeoutNanos := k.stakeibcKeeper.GetParam(ctx, stakeibctypes.KeyIBCTransferTimeoutNanos)
timeoutTimestamp := uint64(ctx.BlockTime().UnixNano()) + ibcTransferTimeoutNanos
channelId := packetMetadata.TransferChannel
if channelId == "" {
channelId = hostZone.TransferChannelId
}
transferMsg := &transfertypes.MsgTransfer{
SourcePort: transfertypes.PortID,
SourceChannel: channelId,
Token: stAsset,
Sender: sender,
Receiver: packetMetadata.IbcReceiver,
TimeoutTimestamp: timeoutTimestamp,
// TimeoutHeight: clienttypes.Height{},
// Memo: "stTokenIBCTransfer",
}

_, err := k.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), transferMsg)
return err
}
4 changes: 2 additions & 2 deletions x/autopilot/keeper/liquidstake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (suite *KeeperTestSuite) TestLiquidStakeOnRecvPacket() {

strdDenom := "ustrd"
prefixedDenom = transfertypes.GetPrefixedDenom(packet.GetSourcePort(), packet.GetSourceChannel(), strdDenom)
strdIbcDenom := transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom()
strdFullDenomPath := transfertypes.ParseDenomTrace(prefixedDenom).GetFullDenomPath()

addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address().Bytes())
testCases := []struct {
Expand Down Expand Up @@ -82,7 +82,7 @@ func (suite *KeeperTestSuite) TestLiquidStakeOnRecvPacket() {
{ // strd denom
forwardingActive: true,
packetData: transfertypes.FungibleTokenPacketData{
Denom: strdIbcDenom,
Denom: strdFullDenomPath,
Amount: "1000000",
Sender: "cosmos16plylpsgxechajltx9yeseqexzdzut9g8vla4k",
Receiver: getStakeibcPacketMetadata(addr1.String(), "LiquidStake"),
Expand Down
Loading
Loading