diff --git a/bindings/generated/ccip/ccip_dummy_receiver/ccip_dummy_receiver/dummy_receiver.go b/bindings/generated/ccip/ccip_dummy_receiver/ccip_dummy_receiver/dummy_receiver.go index 61e399f2d..b15f00a78 100644 --- a/bindings/generated/ccip/ccip_dummy_receiver/ccip_dummy_receiver/dummy_receiver.go +++ b/bindings/generated/ccip/ccip_dummy_receiver/ccip_dummy_receiver/dummy_receiver.go @@ -19,7 +19,7 @@ var ( _ = big.NewInt ) -const FunctionInfo = `[{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"ccip_receive","parameters":[{"name":"expected_message_id","type":"vector"},{"name":"ref","type":"CCIPObjectRef"},{"name":"message","type":"client::Any2SuiMessage"},{"name":"_","type":"Clock"},{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_counter","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_dest_token_amounts","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_amount_amount","parameters":[{"name":"token_amount","type":"TokenAmount"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_amount_token","parameters":[{"name":"token_amount","type":"TokenAmount"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_receiver","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_and_send_coin","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"_","type":"OwnerCap"},{"name":"coin_receiving","type":"Receiving>"},{"name":"recipient","type":"address"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_and_send_coin_no_owner_cap","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"coin_receiving","type":"Receiving>"},{"name":"recipient","type":"address"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_coin","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"_","type":"OwnerCap"},{"name":"coin_receiving","type":"Receiving>"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_coin_no_owner_cap","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"coin_receiving","type":"Receiving>"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"register_receiver","parameters":[{"name":"owner_cap","type":"OwnerCap"},{"name":"ref","type":"CCIPObjectRef"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"type_and_version","parameters":null}]` +const FunctionInfo = `[{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"ccip_receive","parameters":[{"name":"expected_message_id","type":"vector"},{"name":"ref","type":"CCIPObjectRef"},{"name":"message","type":"client::Any2SuiMessage"},{"name":"_","type":"Clock"},{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"disable_always_abort","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"owner_cap","type":"OwnerCap"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"enable_always_abort","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"owner_cap","type":"OwnerCap"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_always_abort","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_counter","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_dest_token_amounts","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_amount_amount","parameters":[{"name":"token_amount","type":"TokenAmount"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_amount_token","parameters":[{"name":"token_amount","type":"TokenAmount"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"get_token_receiver","parameters":[{"name":"state","type":"CCIPReceiverState"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_and_send_coin","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"_","type":"OwnerCap"},{"name":"coin_receiving","type":"Receiving>"},{"name":"recipient","type":"address"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_and_send_coin_no_owner_cap","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"coin_receiving","type":"Receiving>"},{"name":"recipient","type":"address"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_coin","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"_","type":"OwnerCap"},{"name":"coin_receiving","type":"Receiving>"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"receive_coin_no_owner_cap","parameters":[{"name":"state","type":"CCIPReceiverState"},{"name":"coin_receiving","type":"Receiving>"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"register_receiver","parameters":[{"name":"owner_cap","type":"OwnerCap"},{"name":"ref","type":"CCIPObjectRef"}]},{"package":"ccip_dummy_receiver","module":"dummy_receiver","name":"type_and_version","parameters":null}]` type IDummyReceiver interface { TypeAndVersion(ctx context.Context, opts *bind.CallOpts) (*models.SuiTransactionBlockResponse, error) @@ -34,6 +34,9 @@ type IDummyReceiver interface { ReceiveAndSendCoinNoOwnerCap(ctx context.Context, opts *bind.CallOpts, typeArgs []string, state bind.Object, coinReceiving bind.Object, recipient string) (*models.SuiTransactionBlockResponse, error) ReceiveCoinNoOwnerCap(ctx context.Context, opts *bind.CallOpts, typeArgs []string, state bind.Object, coinReceiving bind.Object) (*models.SuiTransactionBlockResponse, error) CcipReceive(ctx context.Context, opts *bind.CallOpts, expectedMessageId []byte, ref bind.Object, message bind.Object, param bind.Object, state bind.Object) (*models.SuiTransactionBlockResponse, error) + GetAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object) (*models.SuiTransactionBlockResponse, error) + EnableAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object, ownerCap bind.Object) (*models.SuiTransactionBlockResponse, error) + DisableAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object, ownerCap bind.Object) (*models.SuiTransactionBlockResponse, error) DevInspect() IDummyReceiverDevInspect Encoder() DummyReceiverEncoder Bound() bind.IBoundContract @@ -48,6 +51,7 @@ type IDummyReceiverDevInspect interface { GetTokenAmountAmount(ctx context.Context, opts *bind.CallOpts, tokenAmount TokenAmount) (*big.Int, error) ReceiveCoin(ctx context.Context, opts *bind.CallOpts, typeArgs []string, state bind.Object, param bind.Object, coinReceiving bind.Object) (any, error) ReceiveCoinNoOwnerCap(ctx context.Context, opts *bind.CallOpts, typeArgs []string, state bind.Object, coinReceiving bind.Object) (any, error) + GetAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object) (bool, error) } type DummyReceiverEncoder interface { @@ -75,6 +79,12 @@ type DummyReceiverEncoder interface { ReceiveCoinNoOwnerCapWithArgs(typeArgs []string, args ...any) (*bind.EncodedCall, error) CcipReceive(expectedMessageId []byte, ref bind.Object, message bind.Object, param bind.Object, state bind.Object) (*bind.EncodedCall, error) CcipReceiveWithArgs(args ...any) (*bind.EncodedCall, error) + GetAlwaysAbort(state bind.Object) (*bind.EncodedCall, error) + GetAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) + EnableAlwaysAbort(state bind.Object, ownerCap bind.Object) (*bind.EncodedCall, error) + EnableAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) + DisableAlwaysAbort(state bind.Object, ownerCap bind.Object) (*bind.EncodedCall, error) + DisableAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) } type DummyReceiverContract struct { @@ -133,6 +143,10 @@ type ReceivedMessage struct { DestTokenAmounts []TokenAmount `move:"vector"` } +type AlwaysAbortToggled struct { + AlwaysAbort bool `move:"bool"` +} + type CCIPReceiverState struct { Id string `move:"sui::object::UID"` Counter uint64 `move:"u64"` @@ -144,6 +158,7 @@ type CCIPReceiverState struct { TokenReceiver string `move:"address"` DestTokenTransferLength uint64 `move:"u64"` DestTokenAmounts []TokenAmount `move:"vector"` + AlwaysAbort bool `move:"bool"` } type DummyReceiverProof struct { @@ -181,6 +196,7 @@ type bcsCCIPReceiverState struct { TokenReceiver [32]byte DestTokenTransferLength uint64 DestTokenAmounts []TokenAmount + AlwaysAbort bool } func convertCCIPReceiverStateFromBCS(bcs bcsCCIPReceiverState) (CCIPReceiverState, error) { @@ -196,6 +212,7 @@ func convertCCIPReceiverStateFromBCS(bcs bcsCCIPReceiverState) (CCIPReceiverStat TokenReceiver: fmt.Sprintf("0x%x", bcs.TokenReceiver), DestTokenTransferLength: bcs.DestTokenTransferLength, DestTokenAmounts: bcs.DestTokenAmounts, + AlwaysAbort: bcs.AlwaysAbort, }, nil } @@ -282,6 +299,23 @@ func init() { } return results, nil }) + bind.RegisterStructDecoder("ccip_dummy_receiver::dummy_receiver::AlwaysAbortToggled", func(data []byte) (interface{}, error) { + var result AlwaysAbortToggled + _, err := mystenbcs.Unmarshal(data, &result) + if err != nil { + return nil, err + } + return result, nil + }) + // Register vector decoder for AlwaysAbortToggled + bind.RegisterStructDecoder("vector", func(data []byte) (interface{}, error) { + var results []AlwaysAbortToggled + _, err := mystenbcs.Unmarshal(data, &results) + if err != nil { + return nil, err + } + return results, nil + }) bind.RegisterStructDecoder("ccip_dummy_receiver::dummy_receiver::CCIPReceiverState", func(data []byte) (interface{}, error) { var temp bcsCCIPReceiverState _, err := mystenbcs.Unmarshal(data, &temp) @@ -500,6 +534,36 @@ func (c *DummyReceiverContract) CcipReceive(ctx context.Context, opts *bind.Call return c.ExecuteTransaction(ctx, opts, encoded) } +// GetAlwaysAbort executes the get_always_abort Move function. +func (c *DummyReceiverContract) GetAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object) (*models.SuiTransactionBlockResponse, error) { + encoded, err := c.dummyReceiverEncoder.GetAlwaysAbort(state) + if err != nil { + return nil, fmt.Errorf("failed to encode function call: %w", err) + } + + return c.ExecuteTransaction(ctx, opts, encoded) +} + +// EnableAlwaysAbort executes the enable_always_abort Move function. +func (c *DummyReceiverContract) EnableAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object, ownerCap bind.Object) (*models.SuiTransactionBlockResponse, error) { + encoded, err := c.dummyReceiverEncoder.EnableAlwaysAbort(state, ownerCap) + if err != nil { + return nil, fmt.Errorf("failed to encode function call: %w", err) + } + + return c.ExecuteTransaction(ctx, opts, encoded) +} + +// DisableAlwaysAbort executes the disable_always_abort Move function. +func (c *DummyReceiverContract) DisableAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object, ownerCap bind.Object) (*models.SuiTransactionBlockResponse, error) { + encoded, err := c.dummyReceiverEncoder.DisableAlwaysAbort(state, ownerCap) + if err != nil { + return nil, fmt.Errorf("failed to encode function call: %w", err) + } + + return c.ExecuteTransaction(ctx, opts, encoded) +} + // TypeAndVersion executes the type_and_version Move function using DevInspect to get return values. // // Returns: 0x1::string::String @@ -668,6 +732,28 @@ func (d *DummyReceiverDevInspect) ReceiveCoinNoOwnerCap(ctx context.Context, opt return results[0], nil } +// GetAlwaysAbort executes the get_always_abort Move function using DevInspect to get return values. +// +// Returns: bool +func (d *DummyReceiverDevInspect) GetAlwaysAbort(ctx context.Context, opts *bind.CallOpts, state bind.Object) (bool, error) { + encoded, err := d.contract.dummyReceiverEncoder.GetAlwaysAbort(state) + if err != nil { + return false, fmt.Errorf("failed to encode function call: %w", err) + } + results, err := d.contract.Call(ctx, opts, encoded) + if err != nil { + return false, err + } + if len(results) == 0 { + return false, fmt.Errorf("no return value") + } + result, ok := results[0].(bool) + if !ok { + return false, fmt.Errorf("unexpected return type: expected bool, got %T", results[0]) + } + return result, nil +} + type dummyReceiverEncoder struct { *bind.BoundContract } @@ -1064,3 +1150,91 @@ func (c dummyReceiverEncoder) CcipReceiveWithArgs(args ...any) (*bind.EncodedCal typeParamsList := []string{} return c.EncodeCallArgsWithGenerics("ccip_receive", typeArgsList, typeParamsList, expectedParams, args, nil) } + +// GetAlwaysAbort encodes a call to the get_always_abort Move function. +func (c dummyReceiverEncoder) GetAlwaysAbort(state bind.Object) (*bind.EncodedCall, error) { + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("get_always_abort", typeArgsList, typeParamsList, []string{ + "&CCIPReceiverState", + }, []any{ + state, + }, []string{ + "bool", + }) +} + +// GetAlwaysAbortWithArgs encodes a call to the get_always_abort Move function using arbitrary arguments. +// This method allows passing both regular values and transaction.Argument values for PTB chaining. +func (c dummyReceiverEncoder) GetAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) { + expectedParams := []string{ + "&CCIPReceiverState", + } + + if len(args) != len(expectedParams) { + return nil, fmt.Errorf("expected %d arguments, got %d", len(expectedParams), len(args)) + } + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("get_always_abort", typeArgsList, typeParamsList, expectedParams, args, []string{ + "bool", + }) +} + +// EnableAlwaysAbort encodes a call to the enable_always_abort Move function. +func (c dummyReceiverEncoder) EnableAlwaysAbort(state bind.Object, ownerCap bind.Object) (*bind.EncodedCall, error) { + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("enable_always_abort", typeArgsList, typeParamsList, []string{ + "&mut CCIPReceiverState", + "&OwnerCap", + }, []any{ + state, + ownerCap, + }, nil) +} + +// EnableAlwaysAbortWithArgs encodes a call to the enable_always_abort Move function using arbitrary arguments. +// This method allows passing both regular values and transaction.Argument values for PTB chaining. +func (c dummyReceiverEncoder) EnableAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) { + expectedParams := []string{ + "&mut CCIPReceiverState", + "&OwnerCap", + } + + if len(args) != len(expectedParams) { + return nil, fmt.Errorf("expected %d arguments, got %d", len(expectedParams), len(args)) + } + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("enable_always_abort", typeArgsList, typeParamsList, expectedParams, args, nil) +} + +// DisableAlwaysAbort encodes a call to the disable_always_abort Move function. +func (c dummyReceiverEncoder) DisableAlwaysAbort(state bind.Object, ownerCap bind.Object) (*bind.EncodedCall, error) { + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("disable_always_abort", typeArgsList, typeParamsList, []string{ + "&mut CCIPReceiverState", + "&OwnerCap", + }, []any{ + state, + ownerCap, + }, nil) +} + +// DisableAlwaysAbortWithArgs encodes a call to the disable_always_abort Move function using arbitrary arguments. +// This method allows passing both regular values and transaction.Argument values for PTB chaining. +func (c dummyReceiverEncoder) DisableAlwaysAbortWithArgs(args ...any) (*bind.EncodedCall, error) { + expectedParams := []string{ + "&mut CCIPReceiverState", + "&OwnerCap", + } + + if len(args) != len(expectedParams) { + return nil, fmt.Errorf("expected %d arguments, got %d", len(expectedParams), len(args)) + } + typeArgsList := []string{} + typeParamsList := []string{} + return c.EncodeCallArgsWithGenerics("disable_always_abort", typeArgsList, typeParamsList, expectedParams, args, nil) +} diff --git a/contracts/ccip/ccip_dummy_receiver/Move.lock b/contracts/ccip/ccip_dummy_receiver/Move.lock index 90098a20d..8a02e5cf6 100644 --- a/contracts/ccip/ccip_dummy_receiver/Move.lock +++ b/contracts/ccip/ccip_dummy_receiver/Move.lock @@ -2,7 +2,7 @@ [move] version = 3 -manifest_digest = "1C6BE16887D975D17491CC22293C7D2D1B9640E16E0D54254F0DF6B637EB505B" +manifest_digest = "F2EBB2A1066B9BF2A4DFB071A98BF5B18D7A843D02FAEE91569A5F7BD8391C96" deps_digest = "397E6A9F7A624706DBDFEE056CE88391A15876868FD18A88504DA74EB458D697" dependencies = [ { id = "Bridge", name = "Bridge" }, @@ -14,7 +14,7 @@ dependencies = [ [[move.package]] id = "Bridge" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "f63c9fc78e2171fa174dc43e757ded416c204558", subdir = "crates/sui-framework/packages/bridge" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "d75fae3aa7fa3545b5803980a1e0c965b8bbf48e", subdir = "crates/sui-framework/packages/bridge" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -47,11 +47,11 @@ dependencies = [ [[move.package]] id = "MoveStdlib" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "f63c9fc78e2171fa174dc43e757ded416c204558", subdir = "crates/sui-framework/packages/move-stdlib" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "d75fae3aa7fa3545b5803980a1e0c965b8bbf48e", subdir = "crates/sui-framework/packages/move-stdlib" } [[move.package]] id = "Sui" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "f63c9fc78e2171fa174dc43e757ded416c204558", subdir = "crates/sui-framework/packages/sui-framework" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "d75fae3aa7fa3545b5803980a1e0c965b8bbf48e", subdir = "crates/sui-framework/packages/sui-framework" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -59,7 +59,7 @@ dependencies = [ [[move.package]] id = "SuiSystem" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "f63c9fc78e2171fa174dc43e757ded416c204558", subdir = "crates/sui-framework/packages/sui-system" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "d75fae3aa7fa3545b5803980a1e0c965b8bbf48e", subdir = "crates/sui-framework/packages/sui-system" } dependencies = [ { id = "MoveStdlib", name = "MoveStdlib" }, @@ -67,6 +67,14 @@ dependencies = [ ] [move.toolchain-version] -compiler-version = "1.58.2" +compiler-version = "1.60.1" edition = "2024" flavor = "sui" + +[env] + +[env.testnet] +chain-id = "4c78adac" +original-published-id = "0xb4dcbf61d5f5f447ae448e3c1503a811d83bdc074a8712ebeb241fd649b372e0" +latest-published-id = "0xb4dcbf61d5f5f447ae448e3c1503a811d83bdc074a8712ebeb241fd649b372e0" +published-version = "1" diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ccip_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ccip_dummy_receiver.move index df4fe3802..f8d7c54b8 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ccip_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ccip_dummy_receiver.move @@ -31,6 +31,10 @@ public struct ReceivedMessage has copy, drop { dest_token_amounts: vector, } +public struct AlwaysAbortToggled has copy, drop { + always_abort: bool, +} + public struct CCIPReceiverState has key { id: UID, counter: u64, @@ -42,6 +46,7 @@ public struct CCIPReceiverState has key { token_receiver: address, dest_token_transfer_length: u64, dest_token_amounts: vector, + always_abort: bool, } public struct DummyReceiverProof has drop {} @@ -69,6 +74,7 @@ fun init(otw: DUMMY_RECEIVER, ctx: &mut TxContext) { token_receiver: @0x0, dest_token_transfer_length: 0, dest_token_amounts: vector[], + always_abort: false, }; let mut owner_cap = OwnerCap { @@ -151,6 +157,9 @@ public fun ccip_receive( _: &Clock, // this is a precompile, but remain the same across all messages state: &mut CCIPReceiverState, // this is a singleton, but remain the same across all messages ) { + // Check if always_abort is enabled + assert!(!state.always_abort, 1); + let ( message_id, source_chain_selector, @@ -163,6 +172,11 @@ public fun ccip_receive( assert!(message_id == expected_message_id, EMessageIdMismatch); + // Check if the data content is "abort" + if (data == b"abort") { + abort 1 + }; + state.counter = state.counter + 1; state.message_id = message_id; state.source_chain_selector = source_chain_selector; @@ -189,3 +203,20 @@ public fun ccip_receive( dest_token_amounts: state.dest_token_amounts, }); } + +public fun get_always_abort(state: &CCIPReceiverState): bool { + state.always_abort +} + +public fun enable_always_abort(state: &mut CCIPReceiverState, owner_cap: &OwnerCap) { + set_always_abort(state, owner_cap, true); +} + +public fun disable_always_abort(state: &mut CCIPReceiverState, owner_cap: &OwnerCap) { + set_always_abort(state, owner_cap, false); +} + +fun set_always_abort(state: &mut CCIPReceiverState, _: &OwnerCap, always_abort: bool) { + state.always_abort = always_abort; + event::emit(AlwaysAbortToggled { always_abort }); +}