Skip to content

Commit

Permalink
feat(precompile): cancel pending bridge call (#584)
Browse files Browse the repository at this point in the history
Co-authored-by: nulnut <151493716+nulnut@users.noreply.github.com>
  • Loading branch information
zakir-code and nulnut committed Jun 28, 2024
1 parent ce62e91 commit fe0324c
Show file tree
Hide file tree
Showing 15 changed files with 504 additions and 13 deletions.
169 changes: 168 additions & 1 deletion contract/ICrossChain.go

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions solidity/contracts/bridge/ICrossChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ interface ICrossChain is IFIP20CrossChain, IBridgeCall {
uint256 _fee
) external payable returns (bool _result);

function cancelPendingBridgeCall(
string memory _chain,
uint256 _txID
) external returns (bool _result);

function bridgeCoinAmount(
address _token,
bytes32 _target
Expand Down Expand Up @@ -72,4 +77,10 @@ interface ICrossChain is IFIP20CrossChain, IBridgeCall {
bytes _data,
bytes _memo
);

event CancelPendingBridgeCallEvent(
address indexed _sender,
string chain,
uint256 txID
);
}
2 changes: 1 addition & 1 deletion tests/contract/CrossChainTest.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions x/crosschain/keeper/bridge_call_refund.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/functionx/fx-core/v7/x/crosschain/types"
)

func (k Keeper) HandleOutgoingBridgeCallRefund(ctx sdk.Context, data *types.OutgoingBridgeCall) {
func (k Keeper) HandleOutgoingBridgeCallRefund(ctx sdk.Context, data *types.OutgoingBridgeCall) sdk.Coins {
refund := types.ExternalAddrToAccAddr(k.moduleName, data.GetRefund())
coins, err := k.bridgeCallTransferCoins(ctx, refund, data.Tokens)
if err != nil {
Expand All @@ -19,12 +19,13 @@ func (k Keeper) HandleOutgoingBridgeCallRefund(ctx sdk.Context, data *types.Outg
))

if k.HasBridgeCallFromMsg(ctx, data.Nonce) {
return
return coins
}
// precompile bridge call, refund to evm
if err = k.bridgeCallTransferTokens(ctx, refund, refund, coins); err != nil {
panic(err)
}
return coins
}

func (k Keeper) DeleteOutgoingBridgeCallRecord(ctx sdk.Context, bridgeCallNonce uint64) {
Expand Down
4 changes: 4 additions & 0 deletions x/crosschain/keeper/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,7 @@ func (k Keeper) PrecompileBridgeCall(ctx sdk.Context, sender, refund common.Addr

return outCallNonce, nil
}

func (k Keeper) PrecompileCancelPendingBridgeCall(ctx sdk.Context, nonce uint64, sender sdk.AccAddress) (sdk.Coins, error) {
return k.HandleCancelPendingOutgoingBridgeCall(ctx, nonce, sender)
}
2 changes: 1 addition & 1 deletion x/crosschain/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ func (s MsgServer) CancelPendingBridgeCall(c context.Context, msg *types.MsgCanc
sender := sdk.MustAccAddressFromBech32(msg.Sender)
ctx := sdk.UnwrapSDKContext(c)

if err := s.HandleCancelPendingOutgoingBridgeCall(ctx, msg.Nonce, sender); err != nil {
if _, err := s.HandleCancelPendingOutgoingBridgeCall(ctx, msg.Nonce, sender); err != nil {
return nil, err
}

Expand Down
21 changes: 13 additions & 8 deletions x/crosschain/keeper/pending_bridge_call_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,30 @@ func (k Keeper) HandlePendingOutgoingBridgeCall(ctx sdk.Context, liquidityProvid
}
}

func (k Keeper) HandleCancelPendingOutgoingBridgeCall(ctx sdk.Context, nonce uint64, sender sdk.AccAddress) error {
func (k Keeper) HandleCancelPendingOutgoingBridgeCall(ctx sdk.Context, nonce uint64, sender sdk.AccAddress) (sdk.Coins, error) {
pendingOutCall, found := k.GetPendingOutgoingBridgeCallByNonce(ctx, nonce)
if !found {
return types.ErrInvalid.Wrapf("not found, nonce: %d", nonce)
return nil, types.ErrInvalid.Wrapf("not found, nonce: %d", nonce)
}

outCall := pendingOutCall.OutgoinBridgeCall
outCallSender := types.ExternalAddrToAccAddr(k.moduleName, outCall.Sender)
if !sender.Equals(outCallSender) {
return types.ErrInvalid.Wrapf("msg.sender %s is not bridge call sender %s", sender.String(), outCallSender.String())
return nil, types.ErrInvalid.Wrapf("msg.sender %s is not bridge call sender %s", sender.String(), outCallSender.String())
}

refundCoins := sdk.NewCoins()
// 1. reuse refund logic
notLiquidTargetCoins := sdk.NewCoins()
for _, coin := range pendingOutCall.NotLiquidCoins {
notLiquidTargetCoin, err := k.erc20Keeper.RefundLiquidity(ctx, outCallSender, coin)
if err != nil {
return types.ErrInvalid.Wrapf("refund liquidity failed, error: %s", err)
return nil, types.ErrInvalid.Wrapf("refund liquidity failed, error: %s", err)
}
notLiquidTargetCoins = notLiquidTargetCoins.Add(notLiquidTargetCoin)
bridgeToken := k.GetDenomBridgeToken(ctx, coin.GetDenom())
if bridgeToken == nil {
return types.ErrInvalid.Wrapf("bridge token not found, denom: %s", coin.GetDenom())
return nil, types.ErrInvalid.Wrapf("bridge token not found, denom: %s", coin.GetDenom())
}
for i := 0; i < len(outCall.Tokens); i++ {
if outCall.Tokens[i].Contract == bridgeToken.Token {
Expand All @@ -146,28 +147,32 @@ func (k Keeper) HandleCancelPendingOutgoingBridgeCall(ctx sdk.Context, nonce uin
}
}

refundCoins = refundCoins.Add(notLiquidTargetCoins...)

if !notLiquidTargetCoins.IsZero() && !k.HasBridgeCallFromMsg(ctx, nonce) {
if err := k.bridgeCallTransferTokens(ctx, outCallSender, outCallSender, notLiquidTargetCoins); err != nil {
panic(err)
}
}

outCall.Refund = outCall.Sender
k.HandleOutgoingBridgeCallRefund(ctx, outCall)
coins := k.HandleOutgoingBridgeCallRefund(ctx, outCall)
refundCoins = refundCoins.Add(coins...)

// 2. refund rewards
if !pendingOutCall.Rewards.IsZero() {
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, k.moduleName, sender, pendingOutCall.Rewards); err != nil {
return err
return nil, err
}
}
refundCoins = refundCoins.Add(pendingOutCall.Rewards...)

// 3. delete pending outgoing bridge call
k.DeletePendingOutgoingBridgeCall(ctx, nonce)

// 4. delete bridge call from msg
k.DeleteBridgeCallFromMsg(ctx, nonce)
return nil
return refundCoins, nil
}

func (k Keeper) HandleAddPendingBridgeCallRewards(ctx sdk.Context, nonce uint64, reward sdk.Coin) (success bool) {
Expand Down
8 changes: 8 additions & 0 deletions x/crosschain/precompile/bridge_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,11 @@ func (m *BridgeCallMethod) PackOutput(nonceNonce *big.Int) ([]byte, error) {
}
return pack, nil
}

func (m *BridgeCallMethod) PackInput(args crosschaintypes.BridgeCallArgs) ([]byte, error) {
arguments, err := m.Method.Inputs.Pack(args.DstChain, args.Refund, args.Tokens, args.Amounts, args.To, args.Data, args.Value, args.Memo)
if err != nil {
return nil, err
}
return append(m.GetMethodId(), arguments...), nil
}
Loading

0 comments on commit fe0324c

Please sign in to comment.