Skip to content

Commit 5a98e59

Browse files
committed
feat: close swaps
1 parent eafe3f5 commit 5a98e59

7 files changed

Lines changed: 183 additions & 17 deletions

File tree

app.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,11 @@ func (app *App) RegisterUpgradeHandler() error {
476476
app.ModuleManager,
477477
app.Configurator(),
478478
app.Logger(),
479-
app.IBCKeeper.ClientKeeper,
479+
app.AccountKeeper.AddressCodec(),
480+
app.AuthorityKeeper,
481+
app.BankKeeper,
482+
app.DollarKeeper,
483+
app.SwapKeeper,
480484
),
481485
)
482486

app.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ modules:
1313
staking,
1414
ibc,
1515
authz,
16-
swap,
1716
ratelimit,
1817
dollar,
1918
]

e2e/upgrade_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ func TestChainUpgrade(t *testing.T) {
2727
t.Skip("skipping test in short mode.")
2828
}
2929

30-
genesisVersion := "v11.4.0"
30+
genesisVersion := "v11.5.0"
3131

3232
upgrades := []e2e.ChainUpgrade{
3333
{
3434
Image: e2e.LocalImages[0],
35-
UpgradeName: "v11.5.0",
35+
UpgradeName: "v11.6.0",
3636
},
3737
}
3838

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,5 @@ replace github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 => gi
392392

393393
// use cosmos compatible syndtr/goleveldb
394394
replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
395+
396+
replace swap.noble.xyz => ../swap

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,5 +2197,3 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
21972197
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
21982198
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
21992199
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
2200-
swap.noble.xyz v1.0.2 h1:ICgXPnXT1ztxE3OzbforQkc0wBjPZ3rbfRllo0GMkpk=
2201-
swap.noble.xyz v1.0.2/go.mod h1:MGzb9tYS7tKYGGGQ0OmUR46cKoCdDpcYR50cvj3Jzms=

upgrade/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package upgrade
1818

1919
// UpgradeName is the name of this specific software upgrade used on-chain.
20-
const UpgradeName = "v11.5.0"
20+
const UpgradeName = "v11.6.0"
2121

2222
// TestnetChainID is the Chain ID of the Noble testnet.
2323
const TestnetChainID = "grand-1"

upgrade/upgrade.go

Lines changed: 173 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,36 @@ package upgrade
1818

1919
import (
2020
"context"
21+
"errors"
22+
"fmt"
23+
"time"
2124

25+
"cosmossdk.io/core/address"
2226
"cosmossdk.io/log"
27+
"cosmossdk.io/math"
2328
upgradetypes "cosmossdk.io/x/upgrade/types"
2429
sdk "github.com/cosmos/cosmos-sdk/types"
2530
"github.com/cosmos/cosmos-sdk/types/module"
26-
clientkeeper "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper"
31+
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
32+
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
33+
swaptypes "swap.noble.xyz/types"
34+
35+
dollarkeeper "dollar.noble.xyz/v2/keeper"
36+
dollartypes "dollar.noble.xyz/v2/types"
37+
authoritykeeper "github.com/noble-assets/authority/keeper"
38+
swapkeeper "swap.noble.xyz/keeper"
39+
stableswaptypes "swap.noble.xyz/types/stableswap"
2740
)
2841

2942
func CreateUpgradeHandler(
3043
mm *module.Manager,
3144
cfg module.Configurator,
3245
logger log.Logger,
33-
clientKeeper clientkeeper.Keeper,
46+
addressCodec address.Codec,
47+
authorityKeeper *authoritykeeper.Keeper,
48+
bankKeeper bankkeeper.Keeper,
49+
dollarKeeper *dollarkeeper.Keeper,
50+
swapKeeper *swapkeeper.Keeper,
3451
) upgradetypes.UpgradeHandler {
3552
return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
3653
vm, err := mm.RunMigrations(ctx, cfg, vm)
@@ -40,18 +57,164 @@ func CreateUpgradeHandler(
4057

4158
sdkCtx := sdk.UnwrapSDKContext(ctx)
4259

43-
// In IBC-Go v8.7.0, the MsgRecoverClient message does not support the
44-
// LegacyAminoJSON signing mode, preventing recovery via the Noble
45-
// Maintenance Multisig. As a result, expired clients on mainnet must
46-
// be manually recovered as part of a software upgrade.
4760
if sdkCtx.ChainID() == MainnetChainID {
48-
// Substitute the IBC light client for the coreum-mainnet-1 chain.
49-
err = clientKeeper.RecoverClient(sdkCtx, "07-tendermint-71", "07-tendermint-226")
50-
if err != nil {
51-
logger.Error("failed to recover coreum-mainnet-1 client", "error", err)
61+
if err = claimSwapPoolsYield(
62+
ctx,
63+
logger,
64+
addressCodec,
65+
authorityKeeper,
66+
bankKeeper,
67+
dollarKeeper,
68+
swapKeeper,
69+
); err != nil {
70+
return vm, err
71+
}
72+
73+
if err = claimSwapPoolsProtocolFees(
74+
ctx,
75+
logger,
76+
swapKeeper,
77+
"noble1c3chgrgr3xcktkpvezxz7g9kl7h64x8tdyd8ng",
78+
); err != nil {
79+
return vm, err
80+
}
81+
82+
if err = closeSwapPools(ctx, logger, swapKeeper); err != nil {
83+
return vm, err
5284
}
5385
}
5486

5587
return vm, nil
5688
}
5789
}
90+
91+
// claimSwapPoolsYield claims the $USDN yield accrued inside the Noble Swap
92+
// pools and sends it to the authority address.
93+
func claimSwapPoolsYield(
94+
ctx context.Context,
95+
logger log.Logger,
96+
addressCodec address.Codec,
97+
authorityKeeper *authoritykeeper.Keeper,
98+
bankKeeper bankkeeper.Keeper,
99+
dollarKeeper *dollarkeeper.Keeper,
100+
swapKeeper *swapkeeper.Keeper,
101+
) error {
102+
authority, err := authorityKeeper.Owner.Get(ctx)
103+
if err != nil {
104+
return errors.New("unable to get underlying authority address from state")
105+
}
106+
authorityBz, err := addressCodec.StringToBytes(authority)
107+
if err != nil {
108+
return errors.New("unable to decode underlying authority address")
109+
}
110+
111+
dollarServer := dollarkeeper.NewMsgServer(dollarKeeper)
112+
113+
pools := swapKeeper.GetPools(ctx)
114+
for _, pool := range pools {
115+
yield, address, err := dollarKeeper.GetYield(ctx, pool.Address)
116+
if err != nil {
117+
return fmt.Errorf("unable to get yield for pool %d", pool.Id)
118+
}
119+
120+
_, err = dollarServer.ClaimYield(ctx, &dollartypes.MsgClaimYield{Signer: pool.Address})
121+
if err != nil {
122+
return fmt.Errorf("unable to claim yield for pool %d", pool.Id)
123+
}
124+
125+
err = bankKeeper.SendCoins(ctx, address, authorityBz, sdk.NewCoins(sdk.NewCoin(dollarKeeper.GetDenom(), yield)))
126+
if err != nil {
127+
return fmt.Errorf("unable to transfer yield for pool %d", pool.Id)
128+
}
129+
130+
logger.Info("claimed swap pool yield", "pool", pool.Id, "yield", yield)
131+
}
132+
133+
return nil
134+
}
135+
136+
// claimSwapPoolsProtocolFees claims the protocol fees accrued inside the Noble Swap
137+
// pools.
138+
func claimSwapPoolsProtocolFees(
139+
ctx context.Context,
140+
logger log.Logger,
141+
swapKeeper *swapkeeper.Keeper,
142+
protocolFeesReceiver string,
143+
) error {
144+
swapServer := swapkeeper.NewMsgServer(swapKeeper)
145+
146+
_, err := swapServer.WithdrawProtocolFees(ctx, &swaptypes.MsgWithdrawProtocolFees{
147+
Signer: authtypes.NewModuleAddressOrBech32Address("authority").String(),
148+
To: protocolFeesReceiver,
149+
})
150+
if err != nil {
151+
logger.Error(err.Error())
152+
}
153+
154+
logger.Info("claimed swap protocol fees")
155+
156+
return nil
157+
}
158+
159+
func closeSwapPools(ctx context.Context, logger log.Logger, swapKeeper *swapkeeper.Keeper) error {
160+
swapServer := swapkeeper.NewStableSwapMsgServer(swapKeeper)
161+
162+
// Iterate all the users that currently have bonded shares, which reflects all the liquidity providers.
163+
itr, err := swapKeeper.Stableswap.UsersTotalBondedShares.Iterate(ctx, nil)
164+
if err != nil {
165+
return err
166+
}
167+
for ; itr.Valid(); itr.Next() {
168+
key, _ := itr.Key()
169+
poolId := key.K1()
170+
userAddress := key.K2()
171+
172+
amount, amountErr := itr.Value()
173+
if amountErr != nil {
174+
return amountErr
175+
}
176+
177+
// Skip users that have already removed all liquidity.
178+
if !amount.IsPositive() {
179+
continue
180+
}
181+
182+
if _, err = swapServer.RemoveLiquidity(ctx, &stableswaptypes.MsgRemoveLiquidity{
183+
Signer: userAddress,
184+
PoolId: poolId,
185+
Percentage: math.LegacyNewDec(100), // 100%
186+
}); err != nil {
187+
return err
188+
}
189+
190+
// In order to trigger an immediate execution we need to update all the unbonding with an EndTime in the past.
191+
unbondEndTime := sdk.UnwrapSDKContext(ctx).HeaderInfo().Time.Add(-24 * 3 * time.Hour)
192+
userTotalAmount := sdk.NewCoins()
193+
for _, position := range swapKeeper.Stableswap.GetUnbondingPositionsByProvider(ctx, userAddress) {
194+
if err = swapKeeper.Stableswap.RemoveUnbondingPosition(ctx, position.Timestamp, position.Address, position.PoolId); err != nil {
195+
return err
196+
}
197+
if err = swapKeeper.Stableswap.SetUnbondingPosition(ctx, unbondEndTime.Unix(), position.Address, position.PoolId, stableswaptypes.UnbondingPosition{
198+
Shares: position.UnbondingPosition.Shares,
199+
Amount: position.UnbondingPosition.Amount,
200+
EndTime: unbondEndTime,
201+
}); err != nil {
202+
return err
203+
}
204+
userTotalAmount = userTotalAmount.Add(position.UnbondingPosition.Amount...)
205+
}
206+
logger.Info("removing liquidy", "pool", poolId, "address", userAddress, "shares", amount.String(), "amount", userTotalAmount.String())
207+
}
208+
209+
// Execute the BeginBlocker.
210+
if err = swapKeeper.BeginBlocker(ctx); err != nil {
211+
return err
212+
}
213+
214+
// As last step, set the pool paused, no further interactions are allowed.
215+
if err = swapKeeper.SetPaused(ctx, 0, true); err != nil {
216+
return err
217+
}
218+
219+
return nil
220+
}

0 commit comments

Comments
 (0)