Skip to content

Commit 7bdb5fa

Browse files
committed
implement IBC transfer on peg in
1 parent 7b1fbdc commit 7bdb5fa

10 files changed

Lines changed: 148 additions & 80 deletions

File tree

app/app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ func New(
680680
app.OracleKeeper,
681681
app.IncentiveKeeper,
682682
app.TSSKeeper,
683+
app.TransferKeeper,
683684
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
684685
)
685686

testutil/keeper/btc_bridge.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func BtcBridgeKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
5050
app.OracleKeeper,
5151
app.IncentiveKeeper,
5252
app.TSSKeeper,
53+
app.TransferKeeper,
5354
authority,
5455
)
5556

x/btcbridge/keeper/deposit.go

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.Msg
2121
return nil, nil, err
2222
}
2323

24-
assetType, recipient, err := k.Mint(ctx, msg.Sender, tx, prevTx, uint64(k.oracleKeeper.GetBlockHeader(ctx, msg.Blockhash).Height))
24+
assetType, recipient, amount, err := k.Mint(ctx, msg.Sender, tx, prevTx, uint64(k.oracleKeeper.GetBlockHeader(ctx, msg.Blockhash).Height))
2525
if err != nil {
2626
return nil, nil, err
2727
}
2828

2929
// hook
3030
if assetType == types.AssetType_ASSET_TYPE_BTC {
31-
if err := k.AfterDeposit(ctx, recipient.EncodeAddress()); err != nil {
31+
if err := k.AfterDeposit(ctx, recipient.EncodeAddress(), *amount, tx.MsgTx()); err != nil {
3232
return nil, nil, err
3333
}
3434
}
@@ -37,10 +37,10 @@ func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.Msg
3737
}
3838

3939
// Mint performs the minting operation of the voucher token
40-
func (k Keeper) Mint(ctx sdk.Context, sender string, tx *btcutil.Tx, prevTx *btcutil.Tx, height uint64) (types.AssetType, btcutil.Address, error) {
40+
func (k Keeper) Mint(ctx sdk.Context, sender string, tx *btcutil.Tx, prevTx *btcutil.Tx, height uint64) (types.AssetType, btcutil.Address, *sdk.Coin, error) {
4141
hash := tx.Hash().String()
4242
if k.existsInHistory(ctx, hash) {
43-
return types.AssetType_ASSET_TYPE_UNSPECIFIED, nil, types.ErrTransactionAlreadyMinted
43+
return types.AssetType_ASSET_TYPE_UNSPECIFIED, nil, nil, types.ErrTransactionAlreadyMinted
4444
}
4545

4646
k.addToMintHistory(ctx, hash)
@@ -53,7 +53,7 @@ func (k Keeper) Mint(ctx sdk.Context, sender string, tx *btcutil.Tx, prevTx *btc
5353
// if the edict is not nil, it indicates that this is a legal runes deposit tx
5454
edict, err := types.CheckRunesDepositTransaction(tx.MsgTx(), params.Vaults)
5555
if err != nil {
56-
return types.AssetType_ASSET_TYPE_UNSPECIFIED, nil, err
56+
return types.AssetType_ASSET_TYPE_UNSPECIFIED, nil, nil, err
5757
}
5858

5959
isRunes := edict != nil
@@ -65,52 +65,57 @@ func (k Keeper) Mint(ctx sdk.Context, sender string, tx *btcutil.Tx, prevTx *btc
6565

6666
// check if the sender is trusted to relay runes deposit
6767
if isRunes && !k.IsTrustedNonBtcRelayer(ctx, sender) {
68-
return assetType, nil, types.ErrUntrustedNonBtcRelayer
68+
return assetType, nil, nil, types.ErrUntrustedNonBtcRelayer
6969
}
7070

7171
// extract the recipient for minting voucher token
7272
recipient, err := types.ExtractRecipientAddr(tx.MsgTx(), prevTx.MsgTx(), params.Vaults, isRunes, chainCfg)
7373
if err != nil {
74-
return assetType, nil, err
74+
return assetType, nil, nil, err
7575
}
7676

77+
var amount *sdk.Coin
78+
7779
if !isRunes {
7880
out, vout, vault, err := k.getOutputForMintBTC(ctx, tx.MsgTx(), chainCfg)
7981
if err != nil {
80-
return assetType, nil, err
82+
return assetType, nil, nil, err
8183
}
8284

83-
if err := k.mintBTC(ctx, tx, height, recipient.EncodeAddress(), vault, out, vout, params.BtcVoucherDenom); err != nil {
84-
return assetType, nil, err
85+
amount, err = k.mintBTC(ctx, tx, height, recipient.EncodeAddress(), vault, out, vout, params.BtcVoucherDenom)
86+
if err != nil {
87+
return assetType, nil, nil, err
8588
}
8689
} else {
8790
outs, vouts, vaults, err := k.getOutputsForMintRunes(ctx, tx.MsgTx(), edict, chainCfg)
8891
if err != nil {
89-
return assetType, nil, err
92+
return assetType, nil, nil, err
9093
}
9194

92-
if err := k.mintRunes(ctx, tx, height, recipient.EncodeAddress(), vaults, outs, vouts, edict.Id, edict.Amount); err != nil {
93-
return assetType, nil, err
95+
amount, err = k.mintRunes(ctx, tx, height, recipient.EncodeAddress(), vaults, outs, vouts, edict.Id, edict.Amount)
96+
if err != nil {
97+
return assetType, nil, nil, err
9498
}
9599
}
96100

97-
return assetType, recipient, nil
101+
return assetType, recipient, amount, nil
98102
}
99103

100-
func (k Keeper) mintBTC(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipient string, vault string, out *wire.TxOut, vout int, denom string) error {
104+
func (k Keeper) mintBTC(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipient string, vault string, out *wire.TxOut, vout int, denom string) (*sdk.Coin, error) {
101105
amount := sdk.NewInt64Coin(denom, out.Value)
102106

103107
recipientAddr, err := sdk.AccAddressFromBech32(recipient)
104108
if err != nil {
105-
return err
109+
return nil, err
106110
}
107111

108112
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount)); err != nil {
109-
return err
113+
return nil, err
110114
}
111115

112-
if err := k.mintBTCWithProtocolFee(ctx, recipientAddr, amount); err != nil {
113-
return err
116+
actualAmount, err := k.mintBTCWithProtocolFee(ctx, recipientAddr, amount)
117+
if err != nil {
118+
return nil, err
114119
}
115120

116121
utxo := types.UTXO{
@@ -125,28 +130,28 @@ func (k Keeper) mintBTC(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipien
125130

126131
k.saveUTXO(ctx, &utxo)
127132

128-
return nil
133+
return actualAmount, nil
129134
}
130135

131-
func (k Keeper) mintRunes(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipient string, vaults []string, outs []*wire.TxOut, vouts []int, id *types.RuneId, amount string) error {
132-
coins := sdk.NewCoins(sdk.NewCoin(id.Denom(), sdkmath.NewIntFromBigInt(types.RuneAmountFromString(amount).Big())))
136+
func (k Keeper) mintRunes(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipient string, vaults []string, outs []*wire.TxOut, vouts []int, id *types.RuneId, amount string) (*sdk.Coin, error) {
137+
coin := sdk.NewCoin(id.Denom(), sdkmath.NewIntFromBigInt(types.RuneAmountFromString(amount).Big()))
133138

134139
recipientAddr, err := sdk.AccAddressFromBech32(recipient)
135140
if err != nil {
136-
return err
141+
return nil, err
137142
}
138143

139-
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil {
140-
return err
144+
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(coin)); err != nil {
145+
return nil, err
141146
}
142147

143-
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipientAddr, coins); err != nil {
144-
return err
148+
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipientAddr, sdk.NewCoins(coin)); err != nil {
149+
return nil, err
145150
}
146151

147152
if k.ProtocolDepositFeeEnabled(ctx) {
148153
if err := k.handleRunesProtocolFee(ctx, tx.Hash().String(), height, outs[1], vouts[1], vaults[1]); err != nil {
149-
return err
154+
return nil, err
150155
}
151156
}
152157

@@ -166,35 +171,38 @@ func (k Keeper) mintRunes(ctx sdk.Context, tx *btcutil.Tx, height uint64, recipi
166171

167172
k.saveUTXO(ctx, &utxo)
168173

169-
return nil
174+
return &coin, nil
170175
}
171176

172177
// mintBTCWithProtocolFee performs btc minting along with the protocol fee handling
173-
func (k Keeper) mintBTCWithProtocolFee(ctx sdk.Context, recipient sdk.AccAddress, amount sdk.Coin) error {
178+
func (k Keeper) mintBTCWithProtocolFee(ctx sdk.Context, recipient sdk.AccAddress, amount sdk.Coin) (*sdk.Coin, error) {
174179
params := k.GetParams(ctx)
175180

176181
var err error
177-
depositAmount := amount
178182

179183
if k.ProtocolDepositFeeEnabled(ctx) {
180184
protocolFee := sdk.NewInt64Coin(params.BtcVoucherDenom, params.ProtocolFees.DepositFee)
181185
protocolFeeCollector := sdk.MustAccAddressFromBech32(params.ProtocolFees.Collector)
182186

183-
depositAmount, err = depositAmount.SafeSub(protocolFee)
187+
amount, err = amount.SafeSub(protocolFee)
184188
if err != nil {
185-
return err
189+
return nil, err
186190
}
187191

188192
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, protocolFeeCollector, sdk.NewCoins(protocolFee)); err != nil {
189-
return err
193+
return nil, err
190194
}
191195
}
192196

193-
if depositAmount.Amount.Int64() < params.ProtocolLimits.BtcMinDeposit {
194-
return types.ErrInvalidDepositAmount
197+
if amount.Amount.Int64() < params.ProtocolLimits.BtcMinDeposit {
198+
return nil, types.ErrInvalidDepositAmount
199+
}
200+
201+
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, sdk.NewCoins(amount)); err != nil {
202+
return nil, err
195203
}
196204

197-
return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, sdk.NewCoins(depositAmount))
205+
return &amount, nil
198206
}
199207

200208
// handleRunesProtocolFee performs the protocol fee handling for runes deposit

x/btcbridge/keeper/hooks.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
package keeper
22

33
import (
4+
"github.com/btcsuite/btcd/wire"
5+
46
sdk "github.com/cosmos/cosmos-sdk/types"
7+
8+
"github.com/sideprotocol/side/x/btcbridge/types"
59
)
610

711
// AfterDeposit performs the extended logic after deposit
8-
func (k Keeper) AfterDeposit(ctx sdk.Context, addr string) error {
9-
// distribute deposit reward
12+
func (k Keeper) AfterDeposit(ctx sdk.Context, addr string, amount sdk.Coin, tx *wire.MsgTx) error {
13+
// distribute deposit reward if enabled
1014
if k.incentiveKeeper.DepositIncentiveEnabled(ctx) {
1115
_ = k.incentiveKeeper.DistributeDepositReward(ctx, addr)
1216
}
1317

18+
// perform IBC transfer if enabled
19+
script := types.GetIBCTransferScript(tx)
20+
if len(script) != 0 {
21+
channelId, recipient, err := types.ParseIBCTransferScript(script)
22+
if err == nil {
23+
_ = k.IBCTransfer(ctx, addr, recipient, amount, channelId)
24+
}
25+
}
26+
1427
return nil
1528
}
1629

x/btcbridge/keeper/ibc.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ import (
1212
"github.com/sideprotocol/side/x/btcbridge/types"
1313
)
1414

15+
// IBCTransfer transfers the specified token via IBC
16+
func (k Keeper) IBCTransfer(ctx sdk.Context, sender string, recipient string, token sdk.Coin, channelId string) error {
17+
msg := &transfertypes.MsgTransfer{
18+
SourcePort: types.DefaultPortId,
19+
SourceChannel: channelId,
20+
Token: token,
21+
Sender: sender,
22+
Receiver: recipient,
23+
TimeoutHeight: clienttypes.NewHeight(0, 0),
24+
TimeoutTimestamp: 0,
25+
Memo: types.DefaultMemo,
26+
}
27+
28+
if _, err := k.ibctransferKeeper.Transfer(ctx, msg); err != nil {
29+
return err
30+
}
31+
32+
return nil
33+
}
34+
1535
// AddToIBCWithdrawRequestQueue adds the given packet to IBC withdrawal queue for sBTC
1636
func (k Keeper) AddToIBCWithdrawRequestQueue(ctx sdk.Context, sequence uint64, recipient string, amount int64) {
1737
store := ctx.KVStore(k.storeKey)
@@ -62,9 +82,9 @@ func (k Keeper) IterateIBCWithdrawRequestQueue(ctx sdk.Context, cb func(req *typ
6282
}
6383
}
6484

65-
// CheckSBTCAutoPegout returns true if the given packet is sBTC transfer and auto-pegout enabled, false otherwise
66-
func (k Keeper) CheckSBTCAutoPegout(ctx sdk.Context, packet transfertypes.FungibleTokenPacketData) bool {
67-
return packet.Denom == k.BtcDenom(ctx) && packet.Memo == types.TagAutoPegout
85+
// CheckSBTCAutoPegOut returns true if the given packet is sBTC transfer and auto-pegout enabled, false otherwise
86+
func (k Keeper) CheckSBTCAutoPegOut(ctx sdk.Context, packet transfertypes.FungibleTokenPacketData) bool {
87+
return packet.Denom == k.BtcDenom(ctx) && packet.Memo == types.FlagAutoPegOut
6888
}
6989

7090
// IBCSendPacketCallback implements IBC callbacks
@@ -121,7 +141,7 @@ func (k Keeper) IBCReceivePacketCallback(
121141

122142
// parse the transfer packet
123143
tranferPacket, ok := tryGetTransferPacket(packet)
124-
if !ok || !k.CheckSBTCAutoPegout(ctx, tranferPacket) {
144+
if !ok || !k.CheckSBTCAutoPegOut(ctx, tranferPacket) {
125145
return nil
126146
}
127147

x/btcbridge/keeper/keeper.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ type (
2626
storeKey storetypes.StoreKey
2727
memKey storetypes.StoreKey
2828

29-
bankKeeper types.BankKeeper
30-
stakingKeeper types.StakingKeeper
31-
oracleKeeper types.OracleKeeper
32-
incentiveKeeper types.IncentiveKeeper
33-
tssKeeper types.TSSKeeper
29+
bankKeeper types.BankKeeper
30+
stakingKeeper types.StakingKeeper
31+
oracleKeeper types.OracleKeeper
32+
incentiveKeeper types.IncentiveKeeper
33+
tssKeeper types.TSSKeeper
34+
ibctransferKeeper types.IBCTransferKeeper
3435

3536
authority string
3637
}
@@ -45,19 +46,21 @@ func NewKeeper(
4546
oracleKeeper types.OracleKeeper,
4647
incentiveKeeper types.IncentiveKeeper,
4748
tssKeeper types.TSSKeeper,
49+
ibctransferKeeper types.IBCTransferKeeper,
4850
authority string,
4951
) *Keeper {
5052
return &Keeper{
51-
cdc: cdc,
52-
storeKey: storeKey,
53-
memKey: memKey,
54-
bankKeeper: bankKeeper,
55-
stakingKeeper: stakingKeeper,
56-
oracleKeeper: oracleKeeper,
57-
incentiveKeeper: incentiveKeeper,
58-
tssKeeper: tssKeeper,
59-
BaseUTXOKeeper: *NewBaseUTXOKeeper(cdc, storeKey),
60-
authority: authority,
53+
cdc: cdc,
54+
storeKey: storeKey,
55+
memKey: memKey,
56+
bankKeeper: bankKeeper,
57+
stakingKeeper: stakingKeeper,
58+
oracleKeeper: oracleKeeper,
59+
incentiveKeeper: incentiveKeeper,
60+
tssKeeper: tssKeeper,
61+
ibctransferKeeper: ibctransferKeeper,
62+
BaseUTXOKeeper: *NewBaseUTXOKeeper(cdc, storeKey),
63+
authority: authority,
6164
}
6265
}
6366

x/btcbridge/keeper/keeper_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func (suite *KeeperTestSuite) TestMintRunes() {
123123
balanceBefore := suite.app.BankKeeper.GetBalance(suite.ctx, sdk.MustAccAddressFromBech32(suite.sender), denom)
124124
suite.True(balanceBefore.Amount.IsZero(), "%s balance before mint should be zero", denom)
125125

126-
assetType, recipient, err := suite.app.BtcBridgeKeeper.Mint(suite.ctx, suite.sender, btcutil.NewTx(tx), btcutil.NewTx(tx), 0)
126+
assetType, recipient, _, err := suite.app.BtcBridgeKeeper.Mint(suite.ctx, suite.sender, btcutil.NewTx(tx), btcutil.NewTx(tx), 0)
127127
suite.NoError(err)
128128
suite.Equal(assetType, types.AssetType_ASSET_TYPE_RUNES)
129129
suite.Equal(suite.sender, recipient.EncodeAddress(), "incorrect recipient")

x/btcbridge/types/errors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ var (
6262

6363
ErrInvalidConsolidation = errorsmod.Register(ModuleName, 8100, "invalid consolidation")
6464

65-
ErrInvalidDepositScript = errorsmod.Register(ModuleName, 9000, "invalid deposit script for IBC transfer")
65+
ErrInvalidIBCTransferScript = errorsmod.Register(ModuleName, 9000, "invalid deposit script for IBC transfer")
6666
)

x/btcbridge/types/expected_keepers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
banktype "github.com/cosmos/cosmos-sdk/x/bank/types"
99
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
1010

11+
ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
1112
oracletypes "github.com/sideprotocol/side/x/oracle/types"
1213
tsstypes "github.com/sideprotocol/side/x/tss/types"
1314
)
@@ -61,7 +62,12 @@ type IncentiveKeeper interface {
6162
DistributeWithdrawReward(ctx sdk.Context, addr string) error
6263
}
6364

64-
// TSSKeeper defines the expected TSS keeper interface
65+
// TSSKeeper defines the expected TSS keeper interfaces
6566
type TSSKeeper interface {
6667
GetParams(ctx sdk.Context) tsstypes.Params
6768
}
69+
70+
// IBCTransferKeeper defines the expected IBC transfer interfaces
71+
type IBCTransferKeeper interface {
72+
Transfer(goCtx context.Context, msg *ibctransfertypes.MsgTransfer) (*ibctransfertypes.MsgTransferResponse, error)
73+
}

0 commit comments

Comments
 (0)