diff --git a/bindings/bind/call.go b/bindings/bind/call.go index a3fa9bae..a386adc3 100644 --- a/bindings/bind/call.go +++ b/bindings/bind/call.go @@ -15,7 +15,7 @@ import ( const ( // DefaultGasBudget is the default gas budget for transactions - DefaultGasBudget uint64 = 500_000_000 + DefaultGasBudget uint64 = 10_000_000_000 ) type IBoundContract interface { diff --git a/bindings/mcms_encoder.go b/bindings/mcms_encoder.go index 669af2f6..f8d6f07f 100644 --- a/bindings/mcms_encoder.go +++ b/bindings/mcms_encoder.go @@ -48,7 +48,7 @@ func overrideCall(call *bind.EncodedCall, module, function string) *bind.Encoded // MCMS SDK will call this to encode the entrypoint call // Data is the raw BCS encoded bytes of the final function call -func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams *transaction.Argument, target, module, function, stateObjID string, data []byte) (*bind.EncodedCall, error) { +func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams *transaction.Argument, target, module, function, stateObjID string, data []byte, typeArgs []string) (*bind.EncodedCall, error) { clock := bind.Object{Id: "0x6"} stateObj := bind.Object{Id: stateObjID} registryObj := bind.Object{Id: e.registryObjID} @@ -76,8 +76,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * if err != nil { return nil, err } - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + entrypointCall, err := burnMintTokenPool.Encoder().McmsSetChainRateLimiterConfigsWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams, clock) if err != nil { return nil, err @@ -91,8 +90,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * if err != nil { return nil, err } - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + entrypointCall, err := burnMintTokenPool.Encoder().McmsExecuteOwnershipTransferWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) if err != nil { return nil, err @@ -115,6 +113,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * if ccipRef.Id != stateObj.Id { return nil, fmt.Errorf("ccip ref (%s) does not match state object (%s)", ccipRef.Id, stateObj.Id) } + return feeQuoter.Encoder().McmsUpdatePricesWithOwnerCapWithArgs(ccipRef, registryObj, clock, executingCallbackParams) } @@ -145,6 +144,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } ccipObjectRef := bind.Object{Id: stateObjID} // For accept_ownership, the state object is the CCIP object ref stateObj := bind.Object{Id: toHexString(deserializeFirst32Bytes(data))} + return offramp.Encoder().McmsAcceptOwnershipWithArgs(ccipObjectRef, stateObj, registryObj, executingCallbackParams) } @@ -162,6 +162,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } ccipObjectRef := bind.Object{Id: stateObjID} // For accept_ownership, the state object is the CCIP object ref stateObj := bind.Object{Id: toHexString(deserializeFirst32Bytes(data))} + return onramp.Encoder().McmsAcceptOwnershipWithArgs(ccipObjectRef, stateObj, registryObj, executingCallbackParams) case "set_dynamic_config", @@ -179,10 +180,10 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * nonceManagerCapObj := bind.Object{Id: toHexString(nonceManagerCap)} sourceTransferCapObj := bind.Object{Id: toHexString(sourceTransferCap)} - if toHexString(state) != stateObj.Id { return nil, fmt.Errorf("state (%s) does not match state object (%s)", toHexString(state), stateObj.Id) } + return onramp.Encoder().McmsInitializeWithArgs(stateObj, registryObj, nonceManagerCapObj, sourceTransferCapObj, executingCallbackParams) case "withdraw_fee_tokens": deserializer := bcs.NewDeserializer(data) @@ -197,8 +198,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * if toHexString(state) != stateObj.Id { return nil, fmt.Errorf("state (%s) does not match state object (%s)", toHexString(state), stateObj.Id) } - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + return onramp.Encoder().McmsWithdrawFeeTokensWithArgs(typeArgs, ccipRef, stateObj, registryObj, coinMetadata, executingCallbackParams) } @@ -221,8 +221,6 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } switch function { case "accept_ownership": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} return burnMintTokenPool.Encoder().McmsAcceptOwnershipWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "set_allowlist_enabled", "apply_allowlist_updates", @@ -235,6 +233,10 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * case "set_chain_rate_limiter_configs", "set_chain_rate_limiter_config": return encodeDefaultWithTypeArgsAndClock() + case "set_pool": + ccipRefBytes := deserializeFirst32Bytes(data) + ccipRef := bind.Object{Id: toHexString(ccipRefBytes)} + return burnMintTokenPool.Encoder().McmsSetPoolWithArgs(typeArgs, ccipRef, stateObj, registryObj, executingCallbackParams) } // LOCK RELEASE TOKEN POOL @@ -245,8 +247,6 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } switch function { case "accept_ownership": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} return lockReleaseTokenPool.Encoder().McmsAcceptOwnershipWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "set_rebalancer", "set_allowlist_enabled", @@ -260,6 +260,10 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * case "set_chain_rate_limiter_configs", "set_chain_rate_limiter_config": return encodeDefaultWithTypeArgsAndClock() + case "set_pool": + ccipRefBytes := deserializeFirst32Bytes(data) + ccipRef := bind.Object{Id: toHexString(ccipRefBytes)} + return lockReleaseTokenPool.Encoder().McmsSetPoolWithArgs(typeArgs, ccipRef, stateObj, registryObj, executingCallbackParams) } @@ -271,8 +275,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } switch function { case "accept_ownership": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + return managedTokenPool.Encoder().McmsAcceptOwnershipWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "set_allowlist_enabled", "apply_allowlist_updates", @@ -285,6 +288,11 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * case "set_chain_rate_limiter_configs", "set_chain_rate_limiter_config": return encodeDefaultWithTypeArgsAndClock() + case "set_pool": + ccipRefBytes := deserializeFirst32Bytes(data) + ccipRef := bind.Object{Id: toHexString(ccipRefBytes)} + return managedTokenPool.Encoder().McmsSetPoolWithArgs(typeArgs, ccipRef, stateObj, registryObj, executingCallbackParams) + } // USDC TOKEN POOL @@ -295,8 +303,7 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } switch function { case "accept_ownership": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + return usdcTokenPool.Encoder().McmsAcceptOwnershipWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "set_allowlist_enabled", "apply_allowlist_updates", @@ -308,6 +315,10 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * return encodeDefaultWithTypeArgs() case "set_chain_rate_limiter_configs", "set_chain_rate_limiter_config": return encodeDefaultWithTypeArgsAndClock() + case "set_pool": + ccipRefBytes := deserializeFirst32Bytes(data) + ccipRef := bind.Object{Id: toHexString(ccipRefBytes)} + return usdcTokenPool.Encoder().McmsSetPoolWithArgs(typeArgs, ccipRef, stateObj, registryObj, executingCallbackParams) } // MANAGED TOKEN @@ -318,19 +329,16 @@ func (e *CCIPEntrypointArgEncoder) EncodeEntryPointArg(executingCallbackParams * } switch function { case "accept_ownership": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + return managedToken.Encoder().McmsAcceptOwnershipWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "configure_new_minter": - // TODO: Find correct type args - typeArgs := []string{"0x1::sui::SUI"} + return managedToken.Encoder().McmsConfigureNewMinterWithArgs(typeArgs, stateObj, registryObj, executingCallbackParams) case "increment_mint_allowance", "set_unlimited_mint_allowances", "blocklist", "unblocklist", "pause": - typeArgs := []string{"0x1::sui::SUI"} deserializer := bcs.NewDeserializer(data) state := deserializer.ReadFixedBytes(SuiAddressLength) deserializer.ReadFixedBytes(SuiAddressLength) // skip owner cap, we don't need it diff --git a/bindings/mcms_encoder_test.go b/bindings/mcms_encoder_test.go index 44306f6d..b78f9a9b 100644 --- a/bindings/mcms_encoder_test.go +++ b/bindings/mcms_encoder_test.go @@ -107,6 +107,7 @@ func TestEncodeEntryPointArg_FeeQuoter(t *testing.T) { "update_prices_with_owner_cap", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -134,6 +135,7 @@ func TestEncodeEntryPointArg_FeeQuoter(t *testing.T) { "apply_fee_token_updates", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -172,6 +174,7 @@ func TestEncodeEntryPointArg_Offramp(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -214,6 +217,7 @@ func TestEncodeEntryPointArg_Onramp(t *testing.T) { "initialize", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -254,6 +258,7 @@ func TestEncodeEntryPointArg_Onramp(t *testing.T) { "withdraw_fee_tokens", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -300,6 +305,7 @@ func TestEncodeEntryPointArg_Onramp(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -337,6 +343,7 @@ func TestEncodeEntryPointArg_Router(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -373,6 +380,7 @@ func TestEncodeEntryPointArg_BurnMintTokenPool(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -402,6 +410,7 @@ func TestEncodeEntryPointArg_BurnMintTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -435,6 +444,7 @@ func TestEncodeEntryPointArg_BurnMintTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -472,6 +482,7 @@ func TestEncodeEntryPointArg_LockReleaseTokenPool(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -502,6 +513,7 @@ func TestEncodeEntryPointArg_LockReleaseTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -535,6 +547,7 @@ func TestEncodeEntryPointArg_LockReleaseTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -572,6 +585,7 @@ func TestEncodeEntryPointArg_ManagedTokenPool(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -601,6 +615,7 @@ func TestEncodeEntryPointArg_ManagedTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -634,6 +649,7 @@ func TestEncodeEntryPointArg_ManagedTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -671,6 +687,7 @@ func TestEncodeEntryPointArg_UsdcTokenPool(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -700,6 +717,7 @@ func TestEncodeEntryPointArg_UsdcTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -733,6 +751,7 @@ func TestEncodeEntryPointArg_UsdcTokenPool(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -770,6 +789,7 @@ func TestEncodeEntryPointArg_ManagedToken(t *testing.T) { "accept_ownership", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -796,6 +816,7 @@ func TestEncodeEntryPointArg_ManagedToken(t *testing.T) { "configure_new_minter", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -834,6 +855,7 @@ func TestEncodeEntryPointArg_ManagedToken(t *testing.T) { fn, stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -869,6 +891,7 @@ func TestEncodeEntryPointArg_UnknownModule(t *testing.T) { "unknown_function", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.NoError(t, err) @@ -899,6 +922,7 @@ func TestEncodeEntryPointArg_ErrorCases(t *testing.T) { "update_prices_with_owner_cap", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.Error(t, err) @@ -920,6 +944,7 @@ func TestEncodeEntryPointArg_ErrorCases(t *testing.T) { "initialize", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.Error(t, err) @@ -941,6 +966,7 @@ func TestEncodeEntryPointArg_ErrorCases(t *testing.T) { "withdraw_fee_tokens", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.Error(t, err) @@ -961,6 +987,7 @@ func TestEncodeEntryPointArg_ErrorCases(t *testing.T) { "pause", stateObjID, data, + []string{"0x1::sui::SUI"}, ) require.Error(t, err) diff --git a/deployment/changesets/cd_deploy_tp_and_configure.go b/deployment/changesets/cd_deploy_tp_and_configure.go deleted file mode 100644 index 30e8bb67..00000000 --- a/deployment/changesets/cd_deploy_tp_and_configure.go +++ /dev/null @@ -1,135 +0,0 @@ -package changesets - -import ( - "fmt" - - cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" - "github.com/smartcontractkit/chainlink-deployments-framework/operations" - "github.com/smartcontractkit/chainlink-sui/bindings/bind" - "github.com/smartcontractkit/chainlink-sui/deployment" - sui_ops "github.com/smartcontractkit/chainlink-sui/deployment/ops" - burnminttokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_burn_mint_token_pool" - lockreleasetokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_lock_release_token_pool" - managedtokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_managed_token_pool" -) - -type DeployTPAndConfigureConfig struct { - SuiChainSelector uint64 - TokenPoolTypes []string - ManagedTPInput managedtokenpoolops.SeqDeployAndInitManagedTokenPoolInput - LockReleaseTPInput lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolInput - BurnMintTpInput burnminttokenpoolops.DeployAndInitBurnMintTokenPoolInput -} - -// ConnectSuiToEVM connects sui chain with EVM -type DeployTPAndConfigure struct{} - -var _ cldf.ChangeSetV2[DeployTPAndConfigureConfig] = DeployTPAndConfigure{} - -// Apply implements deployment.ChangeSetV2. -func (d DeployTPAndConfigure) Apply(e cldf.Environment, config DeployTPAndConfigureConfig) (cldf.ChangesetOutput, error) { - ab := cldf.NewMemoryAddressBook() - state, err := deployment.LoadOnchainStatesui(e) - if err != nil { - return cldf.ChangesetOutput{}, err - } - - seqReports := make([]operations.Report[any, any], 0) - - suiChains := e.BlockChains.SuiChains() - suiChain := suiChains[config.SuiChainSelector] - - deployerAddr, err := suiChain.Signer.GetAddress() - if err != nil { - return cldf.ChangesetOutput{}, err - } - - deps := sui_ops.OpTxDeps{ - Client: suiChain.Client, - Signer: suiChain.Signer, - GetCallOpts: func() *bind.CallOpts { - b := uint64(400_000_000) - return &bind.CallOpts{ - WaitForExecution: true, - GasBudget: &b, - } - }, - } - // the below can be part of (DeployAndInitBurnMintTokenPoolSequence) - // Initialize TP - // ApplyChainUpdates - // SetChainRateLimiterConfigs - // Add remote TP - - for _, tokenPoolType := range config.TokenPoolTypes { - if tokenPoolType == "bnm" { - config.BurnMintTpInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress - config.BurnMintTpInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID - config.BurnMintTpInput.MCMSOwnerAddress = deployerAddr - config.BurnMintTpInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef - config.BurnMintTpInput.TokenPoolAdministrator = deployerAddr // check with felix if this is fine - - BnMTokenPoolSeqReport, err := operations.ExecuteSequence(e.OperationsBundle, burnminttokenpoolops.DeployAndInitBurnMintTokenPoolSequence, deps, config.BurnMintTpInput) - if err != nil { - return cldf.ChangesetOutput{}, err - } - - // save BnM Pool to the addressbook - typeAndVersionBurnMintTokenPool := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolType, deployment.Version1_0_0) - err = ab.Save(config.SuiChainSelector, BnMTokenPoolSeqReport.Output.BurnMintTPPackageID, typeAndVersionBurnMintTokenPool) - if err != nil { - return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPool address %s for Sui chain %d: %w", BnMTokenPoolSeqReport.Output.BurnMintTPPackageID, config.SuiChainSelector, err) - } - - // save BnM Pool State to the addressBook - typeAndVersionBurnMintTokenPoolState := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolStateType, deployment.Version1_0_0) - err = ab.Save(config.SuiChainSelector, BnMTokenPoolSeqReport.Output.Objects.StateObjectId, typeAndVersionBurnMintTokenPoolState) - if err != nil { - return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPoolState address %s for Sui chain %d: %w", BnMTokenPoolSeqReport.Output.Objects.StateObjectId, config.SuiChainSelector, err) - } - - // save BnM Pool OwnerId to the addressBook - typeAndVersionBurnMintTokenPoolOwnerId := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolOwnerIDType, deployment.Version1_0_0) - err = ab.Save(config.SuiChainSelector, BnMTokenPoolSeqReport.Output.Objects.OwnerCapObjectId, typeAndVersionBurnMintTokenPoolOwnerId) - if err != nil { - return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPoolOwnerCapId address %s for Sui chain %d: %w", BnMTokenPoolSeqReport.Output.Objects.OwnerCapObjectId, config.SuiChainSelector, err) - } - } - - if tokenPoolType == "lnr" { - config.LockReleaseTPInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress - config.LockReleaseTPInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID - config.LockReleaseTPInput.MCMSOwnerAddress = deployerAddr - config.LockReleaseTPInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef - config.LockReleaseTPInput.TokenPoolAdministrator = deployerAddr - - _, err = operations.ExecuteSequence(e.OperationsBundle, lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolSequence, deps, config.LockReleaseTPInput) - if err != nil { - return cldf.ChangesetOutput{}, err - } - } - - if tokenPoolType == "managed" { - config.ManagedTPInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress - config.ManagedTPInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID - config.ManagedTPInput.MCMSOwnerAddress = deployerAddr - config.ManagedTPInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef - config.ManagedTPInput.TokenPoolAdministrator = deployerAddr - - _, err = operations.ExecuteSequence(e.OperationsBundle, managedtokenpoolops.DeployAndInitManagedTokenPoolSequence, deps, config.ManagedTPInput) - if err != nil { - return cldf.ChangesetOutput{}, err - } - } - } - - return cldf.ChangesetOutput{ - AddressBook: ab, - Reports: seqReports, - }, nil -} - -// VerifyPreconditions implements deployment.ChangeSetV2. -func (d DeployTPAndConfigure) VerifyPreconditions(e cldf.Environment, config DeployTPAndConfigureConfig) error { - return nil -} diff --git a/deployment/changesets/cs_deploy_managed_token.go b/deployment/changesets/cs_deploy_managed_token.go new file mode 100644 index 00000000..d637af66 --- /dev/null +++ b/deployment/changesets/cs_deploy_managed_token.go @@ -0,0 +1,88 @@ +package changesets + +import ( + "fmt" + + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink-sui/bindings/bind" + "github.com/smartcontractkit/chainlink-sui/deployment" + sui_ops "github.com/smartcontractkit/chainlink-sui/deployment/ops" + managedtokenops "github.com/smartcontractkit/chainlink-sui/deployment/ops/managed_token" +) + +type DeployManagedTokenConfig struct { + managedtokenops.DeployAndInitManagedTokenInput + ChainSelector uint64 `yaml:"chainSelector"` +} + +var _ cldf.ChangeSetV2[DeployManagedTokenConfig] = DeployManagedToken{} + +// DeployAptosChain deploys Sui chain packages and modules +type DeployManagedToken struct{} + +// Apply implements deployment.ChangeSetV2. +func (d DeployManagedToken) Apply(e cldf.Environment, config DeployManagedTokenConfig) (cldf.ChangesetOutput, error) { + ab := cldf.NewMemoryAddressBook() + seqReports := make([]operations.Report[any, any], 0) + + suiChains := e.BlockChains.SuiChains() + + suiChain := suiChains[config.ChainSelector] + + deps := sui_ops.OpTxDeps{ + Client: suiChain.Client, + Signer: suiChain.Signer, + GetCallOpts: func() *bind.CallOpts { + b := uint64(400_000_000) + return &bind.CallOpts{ + WaitForExecution: true, + GasBudget: &b, + } + }, + } + + // Run DeployManagedToken Operation + managedTokenReport, err := operations.ExecuteSequence(e.OperationsBundle, managedtokenops.DeployAndInitManagedTokenSequence, deps, config.DeployAndInitManagedTokenInput) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to deploy ManagedToken for Sui chain %d: %w", config.ChainSelector, err) + } + + // save ManagedToken address to the addressbook + typeAndVersionManagedToken := cldf.NewTypeAndVersion(deployment.SuiManagedTokenType, deployment.Version1_0_0) + err = ab.Save(config.ChainSelector, managedTokenReport.Output.ManagedTokenPackageId, typeAndVersionManagedToken) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedToken address %s for Sui chain %d: %w", managedTokenReport.Output.ManagedTokenPackageId, config.ChainSelector, err) + } + + // save ManagedTokenOwnerCapObjectID address to the addressbook + typeAndVersionOwnerCapObjectID := cldf.NewTypeAndVersion(deployment.SuiManagedTokenOwnerCapObjectID, deployment.Version1_0_0) + err = ab.Save(config.ChainSelector, managedTokenReport.Output.Objects.OwnerCapObjectId, typeAndVersionOwnerCapObjectID) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedToken OwnerCapObjectId address %s for Sui chain %d: %w", managedTokenReport.Output.Objects.OwnerCapObjectId, config.ChainSelector, err) + } + + // save ManagedTokenMinterCapID address to the addressbook + typeAndVersionMinterCapID := cldf.NewTypeAndVersion(deployment.SuiManagedTokenMinterCapID, deployment.Version1_0_0) + err = ab.Save(config.ChainSelector, managedTokenReport.Output.Objects.MinterCapObjectId, typeAndVersionMinterCapID) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedToken MinterCapObjectId address %s for Sui chain %d: %w", managedTokenReport.Output.Objects.MinterCapObjectId, config.ChainSelector, err) + } + + // save ManagedTokenStateObjectID address to the addressbook + typeAndVersionStateObjectID := cldf.NewTypeAndVersion(deployment.SuiManagedTokenStateObjectID, deployment.Version1_0_0) + err = ab.Save(config.ChainSelector, managedTokenReport.Output.Objects.StateObjectId, typeAndVersionStateObjectID) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedToken StateObjectId address %s for Sui chain %d: %w", managedTokenReport.Output.Objects.StateObjectId, config.ChainSelector, err) + } + + return cldf.ChangesetOutput{ + AddressBook: ab, + Reports: seqReports, + }, nil +} + +// VerifyPreconditions implements deployment.ChangeSetV2. +func (d DeployManagedToken) VerifyPreconditions(e cldf.Environment, config DeployManagedTokenConfig) error { + return nil +} diff --git a/deployment/changesets/cs_deploy_tp_and_configure.go b/deployment/changesets/cs_deploy_tp_and_configure.go new file mode 100644 index 00000000..8f6f64aa --- /dev/null +++ b/deployment/changesets/cs_deploy_tp_and_configure.go @@ -0,0 +1,179 @@ +package changesets + +import ( + "fmt" + + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink-sui/bindings/bind" + "github.com/smartcontractkit/chainlink-sui/deployment" + sui_ops "github.com/smartcontractkit/chainlink-sui/deployment/ops" + burnminttokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_burn_mint_token_pool" + lockreleasetokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_lock_release_token_pool" + managedtokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_managed_token_pool" + tokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_token_pool" +) + +type DeployTPAndConfigureConfig struct { + SuiChainSelector uint64 + TokenPoolTypes []string + ManagedTPInput managedtokenpoolops.SeqDeployAndInitManagedTokenPoolInput + LockReleaseTPInput lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolInput + BurnMintTpInput burnminttokenpoolops.DeployAndInitBurnMintTokenPoolInput +} + +// ConnectSuiToEVM connects sui chain with EVM +type DeployTPAndConfigure struct{} + +var _ cldf.ChangeSetV2[DeployTPAndConfigureConfig] = DeployTPAndConfigure{} + +// Apply implements deployment.ChangeSetV2. +func (d DeployTPAndConfigure) Apply(e cldf.Environment, config DeployTPAndConfigureConfig) (cldf.ChangesetOutput, error) { + ab := cldf.NewMemoryAddressBook() + state, err := deployment.LoadOnchainStatesui(e) + if err != nil { + return cldf.ChangesetOutput{}, err + } + + seqReports := make([]operations.Report[any, any], 0) + + suiChains := e.BlockChains.SuiChains() + suiChain := suiChains[config.SuiChainSelector] + + deployerAddr, err := suiChain.Signer.GetAddress() + if err != nil { + return cldf.ChangesetOutput{}, err + } + + deps := sui_ops.OpTxDeps{ + Client: suiChain.Client, + Signer: suiChain.Signer, + GetCallOpts: func() *bind.CallOpts { + b := uint64(400_000_000) + return &bind.CallOpts{ + WaitForExecution: true, + GasBudget: &b, + } + }, + } + + // Populate state information for each token pool type + for _, tokenPoolType := range config.TokenPoolTypes { + switch tokenPoolType { + case "bnm": + config.BurnMintTpInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress + config.BurnMintTpInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID + // TODO: MCMSOwner address should come state + config.BurnMintTpInput.MCMSOwnerAddress = deployerAddr + config.BurnMintTpInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef + config.BurnMintTpInput.TokenPoolAdministrator = deployerAddr + case "lnr": + config.LockReleaseTPInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress + config.LockReleaseTPInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID + config.LockReleaseTPInput.MCMSOwnerAddress = deployerAddr + config.LockReleaseTPInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef + config.LockReleaseTPInput.TokenPoolAdministrator = deployerAddr + case "managed": + config.ManagedTPInput.CCIPPackageId = state[config.SuiChainSelector].CCIPAddress + config.ManagedTPInput.MCMSAddress = state[config.SuiChainSelector].MCMSPackageID + config.ManagedTPInput.MCMSOwnerAddress = deployerAddr + config.ManagedTPInput.CCIPObjectRefObjectId = state[config.SuiChainSelector].CCIPObjectRef + config.ManagedTPInput.TokenPoolAdministrator = deployerAddr + } + } + + // Execute the unified token pool deployment sequence + tokenPoolInput := tokenpoolops.DeployAndInitAllTokenPoolsInput{ + SuiChainSelector: config.SuiChainSelector, + TokenPoolTypes: config.TokenPoolTypes, + ManagedTPInput: config.ManagedTPInput, + LockReleaseTPInput: config.LockReleaseTPInput, + BurnMintTpInput: config.BurnMintTpInput, + } + + tokenPoolReport, err := operations.ExecuteSequence(e.OperationsBundle, tokenpoolops.DeployAndInitAllTokenPoolsSequence, deps, tokenPoolInput) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to deploy token pools: %w", err) + } + + // Save addresses to the address book based on what was deployed + for _, tokenPoolType := range config.TokenPoolTypes { + switch tokenPoolType { + case "bnm": + // save BnM Pool to the addressbook + typeAndVersionBurnMintTokenPool := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.BurnMintTPPackageID, typeAndVersionBurnMintTokenPool) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPool address %s for Sui chain %d: %w", tokenPoolReport.Output.BurnMintTPPackageID, config.SuiChainSelector, err) + } + + // save BnM Pool State to the addressBook + typeAndVersionBurnMintTokenPoolState := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolStateType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployBurnMintTokenPoolOutput.Objects.StateObjectId, typeAndVersionBurnMintTokenPoolState) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPoolState address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployBurnMintTokenPoolOutput.Objects.StateObjectId, config.SuiChainSelector, err) + } + + // save BnM Pool OwnerId to the addressBook + typeAndVersionBurnMintTokenPoolOwnerId := cldf.NewTypeAndVersion(deployment.SuiBnMTokenPoolOwnerIDType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployBurnMintTokenPoolOutput.Objects.OwnerCapObjectId, typeAndVersionBurnMintTokenPoolOwnerId) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save BnMTokenPoolOwnerCapId address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployBurnMintTokenPoolOutput.Objects.OwnerCapObjectId, config.SuiChainSelector, err) + } + + case "lnr": + // save LnR Pool to the addressbook + typeAndVersionLnRTokenPool := cldf.NewTypeAndVersion(deployment.SuiLnRTokenPoolType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.LockReleaseTPPackageID, typeAndVersionLnRTokenPool) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save LnRTokenPool address %s for Sui chain %d: %w", tokenPoolReport.Output.LockReleaseTPPackageID, config.SuiChainSelector, err) + } + + // save LnR Pool State to the addressBook + typeAndVersionLnRTokenPoolState := cldf.NewTypeAndVersion(deployment.SuiLnRTokenPoolStateType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployLockReleaseTokenPoolOutput.Objects.StateObjectId, typeAndVersionLnRTokenPoolState) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save LnRTokenPoolState address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployLockReleaseTokenPoolOutput.Objects.StateObjectId, config.SuiChainSelector, err) + } + + // save LnR Pool OwnerId to the addressBook + typeAndVersionLnRTokenPoolOwnerId := cldf.NewTypeAndVersion(deployment.SuiLnRTokenPoolOwnerIDType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployLockReleaseTokenPoolOutput.Objects.OwnerCapObjectId, typeAndVersionLnRTokenPoolOwnerId) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save LnRTokenPoolOwnerCapId address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployLockReleaseTokenPoolOutput.Objects.OwnerCapObjectId, config.SuiChainSelector, err) + } + + case "managed": + // save Managed Pool to the addressbook + typeAndVersionManagedTokenPool := cldf.NewTypeAndVersion(deployment.SuiManagedTokenPoolType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.ManagedTPPackageId, typeAndVersionManagedTokenPool) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedTokenPool address %s for Sui chain %d: %w", tokenPoolReport.Output.ManagedTPPackageId, config.SuiChainSelector, err) + } + + // save Managed Pool State to the addressBook + typeAndVersionManagedTokenPoolState := cldf.NewTypeAndVersion(deployment.SuiManagedTokenPoolStateType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployManagedTokenPoolOutput.Objects.StateObjectId, typeAndVersionManagedTokenPoolState) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedTokenPoolState address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployManagedTokenPoolOutput.Objects.StateObjectId, config.SuiChainSelector, err) + } + + // save Managed Pool OwnerId to the addressBook + typeAndVersionManagedTokenPoolOwnerId := cldf.NewTypeAndVersion(deployment.SuiManagedTokenPoolOwnerIDType, deployment.Version1_0_0) + err = ab.Save(config.SuiChainSelector, tokenPoolReport.Output.DeployManagedTokenPoolOutput.Objects.OwnerCapObjectId, typeAndVersionManagedTokenPoolOwnerId) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to save ManagedTokenPoolOwnerCapId address %s for Sui chain %d: %w", tokenPoolReport.Output.DeployManagedTokenPoolOutput.Objects.OwnerCapObjectId, config.SuiChainSelector, err) + } + } + } + + return cldf.ChangesetOutput{ + AddressBook: ab, + Reports: seqReports, + }, nil +} + +// VerifyPreconditions implements deployment.ChangeSetV2. +func (d DeployTPAndConfigure) VerifyPreconditions(e cldf.Environment, config DeployTPAndConfigureConfig) error { + return nil +} diff --git a/deployment/changesets/cs_mcms_user_proposal.go b/deployment/changesets/cs_mcms_user_proposal.go index 6695e192..d1feb4ae 100644 --- a/deployment/changesets/cs_mcms_user_proposal.go +++ b/deployment/changesets/cs_mcms_user_proposal.go @@ -68,6 +68,7 @@ func (d InvokeMCMSFunctionOne) Apply(e cldf.Environment, config InvokeMCMSFuncti "MCMSUser", []string{}, config.McmsUserObjectID, + []string{}, ) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to create transaction: %w", err) diff --git a/deployment/go.mod b/deployment/go.mod index 13e439f8..af0fc9d2 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -18,7 +18,7 @@ require ( github.com/smartcontractkit/chainlink-common v0.9.5-0.20250908082700-aa3f5927af8c github.com/smartcontractkit/chainlink-deployments-framework v0.47.0 github.com/smartcontractkit/chainlink-sui v0.0.0-20251016153021-3d4a0208cf70 - github.com/smartcontractkit/mcms v0.28.0 + github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef github.com/stretchr/testify v1.10.0 ) diff --git a/deployment/go.sum b/deployment/go.sum index e58412cb..e339e0fe 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -631,8 +631,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358 h1:+NVzR5LZVazRUunzVn34u+lwnpmn6NTVPCeZOVyQHLo= github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= -github.com/smartcontractkit/mcms v0.28.0 h1:N/zUNRZixSbas7EQ9yk2ksmb9b5M734Tu8pY3F+ErJ4= -github.com/smartcontractkit/mcms v0.28.0/go.mod h1:SYQok8vhBAc9ZdlJ+TKQpJlIQAHcP83KC4fKIBm/j7I= +github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef h1:jgoBu/KzwMsrx1c29DQPD/G7aoGQMch83hRSABbSkF0= +github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef/go.mod h1:SYQok8vhBAc9ZdlJ+TKQpJlIQAHcP83KC4fKIBm/j7I= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= diff --git a/deployment/ops/ccip_burn_mint_token_pool/op_burn_mint_token_pool.go b/deployment/ops/ccip_burn_mint_token_pool/op_burn_mint_token_pool.go index 3a587ddd..eeb5b971 100644 --- a/deployment/ops/ccip_burn_mint_token_pool/op_burn_mint_token_pool.go +++ b/deployment/ops/ccip_burn_mint_token_pool/op_burn_mint_token_pool.go @@ -174,11 +174,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Burn remoteTokenAddressesBytes[i] = b32 } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.ApplyChainUpdates( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().ApplyChainUpdates( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -187,6 +183,30 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Burn remotePoolAddressesBytes, remoteTokenAddressesBytes, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyChainUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyChainUpdates on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool apply chain updates: %w", err) } @@ -197,6 +217,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Burn Digest: tx.Digest, PackageId: input.BurnMintPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -228,11 +249,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetChainRateLimiterConfigs( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetChainRateLimiterConfigs( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -245,6 +262,30 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i input.InboundCapacities, input.InboundRates, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetChainRateLimiterConfigs call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetChainRateLimiterConfigs on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool set configs rate limiter: %w", err) } @@ -255,6 +296,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i Digest: tx.Digest, PackageId: input.BurnMintPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -281,17 +323,37 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input B return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.AddRemotePool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().AddRemotePool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.RemoteChainSelector, []byte(input.RemotePoolAddress), ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode AddRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of AddRemotePool on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool add remote pool: %w", err) } @@ -302,6 +364,7 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input B Digest: tx.Digest, PackageId: input.BurnMintTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -328,17 +391,37 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input BurnMin return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetPool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetPool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.RefObjectId}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.CoinMetadataAddress, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetPool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetPool on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool set pool: %w", err) } @@ -349,6 +432,7 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input BurnMin Digest: tx.Digest, PackageId: input.BurnMintTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -358,3 +442,211 @@ var BurnMintTokenPoolSetPoolOp = cld_ops.NewOperation( "Sets the pool in the token admin registry for the CCIP Burn Mint Token Pool", setPoolHandler, ) + +// BMTP -- set_allowlist_enabled +type BurnMintTokenPoolSetAllowlistEnabledInput struct { + BurnMintPackageId string `json:"burn_mint_package_id"` + StateObjectId string `json:"state_object_id"` + OwnerCap string `json:"owner_cap"` + CoinObjectTypeArg string `json:"coin_object_type_arg"` + Enabled bool `json:"enabled"` +} + +var setAllowlistEnabledHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input BurnMintTokenPoolSetAllowlistEnabledInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_burn_mint_token_pool.NewBurnMintTokenPool(input.BurnMintPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint contract: %w", err) + } + + encodedCall, err := contract.Encoder().SetAllowlistEnabled( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.Enabled, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetAllowlistEnabled call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetAllowlistEnabled on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool set allowlist enabled: %w", err) + } + + b.Logger.Infow("SetAllowlistEnabled on BurnMintTokenPool", "BurnMintTokenPool PackageId:", input.BurnMintPackageId) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var BurnMintTokenPoolSetAllowlistEnabledOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "burn_mint_token_pool", "set_allowlist_enabled"), + semver.MustParse("0.1.0"), + "Sets allowlist enabled in the CCIP Burn Mint Token Pool contract", + setAllowlistEnabledHandler, +) + +// BMTP -- apply_allowlist_updates +type BurnMintTokenPoolApplyAllowlistUpdatesInput struct { + BurnMintPackageId string `json:"burn_mint_package_id"` + StateObjectId string `json:"state_object_id"` + OwnerCap string `json:"owner_cap"` + CoinObjectTypeArg string `json:"coin_object_type_arg"` + Removes []string `json:"removes"` + Adds []string `json:"adds"` +} + +var applyAllowlistUpdatesHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input BurnMintTokenPoolApplyAllowlistUpdatesInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_burn_mint_token_pool.NewBurnMintTokenPool(input.BurnMintPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint contract: %w", err) + } + + encodedCall, err := contract.Encoder().ApplyAllowlistUpdates( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.Removes, + input.Adds, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyAllowlistUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyAllowlistUpdates on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool apply allowlist updates: %w", err) + } + + b.Logger.Infow("ApplyAllowlistUpdates on BurnMintTokenPool", "BurnMintTokenPool PackageId:", input.BurnMintPackageId) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var BurnMintTokenPoolApplyAllowlistUpdatesOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "burn_mint_token_pool", "apply_allowlist_updates"), + semver.MustParse("0.1.0"), + "Applies allowlist updates in the CCIP Burn Mint Token Pool contract", + applyAllowlistUpdatesHandler, +) + +// BMTP -- remove_remote_pool +type BurnMintTokenPoolRemoveRemotePoolInput struct { + BurnMintPackageId string `json:"burn_mint_package_id"` + StateObjectId string `json:"state_object_id"` + OwnerCap string `json:"owner_cap"` + CoinObjectTypeArg string `json:"coin_object_type_arg"` + RemoteChainSelector uint64 `json:"remote_chain_selector"` + RemotePoolAddress string `json:"remote_pool_address"` +} + +var removeRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input BurnMintTokenPoolRemoveRemotePoolInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_burn_mint_token_pool.NewBurnMintTokenPool(input.BurnMintPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create burn mint contract: %w", err) + } + + // Convert string to bytes for RemotePoolAddress + remotePoolAddressBytes, err := deployment.StrToBytes(input.RemotePoolAddress) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert remote pool address to bytes: %w", err) + } + + encodedCall, err := contract.Encoder().RemoveRemotePool( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.RemoteChainSelector, + remotePoolAddressBytes, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode RemoveRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of RemoveRemotePool on BurnMintTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute burn mint token pool remove remote pool: %w", err) + } + + b.Logger.Infow("RemoveRemotePool on BurnMintTokenPool", "BurnMintTokenPool PackageId:", input.BurnMintPackageId) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.BurnMintPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var BurnMintTokenPoolRemoveRemotePoolOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "burn_mint_token_pool", "remove_remote_pool"), + semver.MustParse("0.1.0"), + "Removes remote pool in the CCIP Burn Mint Token Pool contract", + removeRemotePoolHandler, +) diff --git a/deployment/ops/ccip_burn_mint_token_pool/op_deploy.go b/deployment/ops/ccip_burn_mint_token_pool/op_deploy.go index b8c90773..63a7616c 100644 --- a/deployment/ops/ccip_burn_mint_token_pool/op_deploy.go +++ b/deployment/ops/ccip_burn_mint_token_pool/op_deploy.go @@ -118,7 +118,7 @@ var acceptOwnershipBurnMintTokenPoolHandler = func(b cld_ops.Bundle, deps sui_op if err != nil { return sui_ops.OpTxResult[AcceptOwnershipBurnMintTokenPoolObjects]{}, fmt.Errorf("failed to encode AcceptOwnership call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[AcceptOwnershipBurnMintTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_burn_mint_token_pool/op_execute_ownership_transfer_to_mcms.go b/deployment/ops/ccip_burn_mint_token_pool/op_execute_ownership_transfer_to_mcms.go index cd14485c..1647971c 100644 --- a/deployment/ops/ccip_burn_mint_token_pool/op_execute_ownership_transfer_to_mcms.go +++ b/deployment/ops/ccip_burn_mint_token_pool/op_execute_ownership_transfer_to_mcms.go @@ -43,7 +43,7 @@ var executeOwnershipTransferToMcmsBurnMintTokenPoolHandler = func(b cld_ops.Bund if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsBurnMintTokenPoolObjects]{}, fmt.Errorf("failed to encode ExecuteOwnershipTransferToMcms call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsBurnMintTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_burn_mint_token_pool/op_registry.go b/deployment/ops/ccip_burn_mint_token_pool/op_registry.go new file mode 100644 index 00000000..65e06831 --- /dev/null +++ b/deployment/ops/ccip_burn_mint_token_pool/op_registry.go @@ -0,0 +1,25 @@ +package burnminttokenpoolops + +import ( + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// Exports every operation available so they can be registered to be used in dynamic changesets +var AllOperationsBurnMintTP = []cld_ops.Operation[any, any, any]{ + // Deployment Operations + *DeployCCIPBurnMintTokenPoolOp.AsUntyped(), + *TransferOwnershipBurnMintTokenPoolOp.AsUntyped(), + *AcceptOwnershipBurnMintTokenPoolOp.AsUntyped(), + // Token Pool Operations + *BurnMintTokenPoolInitializeOp.AsUntyped(), + *BurnMintTokenPoolInitializeByCcipAdminOp.AsUntyped(), + *BurnMintTokenPoolApplyChainUpdatesOp.AsUntyped(), + *BurnMintTokenPoolSetChainRateLimiterOp.AsUntyped(), + *BurnMintTokenPoolAddRemotePoolOp.AsUntyped(), + *BurnMintTokenPoolSetPoolOp.AsUntyped(), + *BurnMintTokenPoolSetAllowlistEnabledOp.AsUntyped(), + *BurnMintTokenPoolApplyAllowlistUpdatesOp.AsUntyped(), + *BurnMintTokenPoolRemoveRemotePoolOp.AsUntyped(), + // MCMS Operations + *ExecuteOwnershipTransferToMcmsBurnMintTokenPoolOp.AsUntyped(), +} diff --git a/deployment/ops/ccip_burn_mint_token_pool/seq_deploy_and_init.go b/deployment/ops/ccip_burn_mint_token_pool/seq_deploy_and_init.go index 7521b10a..b4e072e5 100644 --- a/deployment/ops/ccip_burn_mint_token_pool/seq_deploy_and_init.go +++ b/deployment/ops/ccip_burn_mint_token_pool/seq_deploy_and_init.go @@ -109,6 +109,20 @@ var DeployAndInitBurnMintTokenPoolSequence = cld_ops.NewSequence( return DeployBurnMintTokenPoolOutput{}, err } + // transfer ownership to MCMS + _, err = cld_ops.ExecuteOperation( + env, + TransferOwnershipBurnMintTokenPoolOp, + deps, + TransferOwnershipBurnMintTokenPoolInput{ + BurnMintTokenPoolPackageId: deployReport.Output.PackageId, + TypeArgs: []string{input.CoinObjectTypeArg}, + StateObjectId: initReport.Output.Objects.StateObjectId, + OwnerCapObjectId: initReport.Output.Objects.OwnerCapObjectId, + To: input.BurnMintTokenPoolDeployInput.MCMSAddress, + }, + ) + return DeployBurnMintTokenPoolOutput{ BurnMintTPPackageID: deployReport.Output.PackageId, Objects: DeployBurnMintTokenPoolObjects{ diff --git a/deployment/ops/ccip_lock_release_token_pool/op_deploy.go b/deployment/ops/ccip_lock_release_token_pool/op_deploy.go index a694245f..a397c7bc 100644 --- a/deployment/ops/ccip_lock_release_token_pool/op_deploy.go +++ b/deployment/ops/ccip_lock_release_token_pool/op_deploy.go @@ -118,7 +118,7 @@ var acceptOwnershipLockReleaseTokenPoolHandler = func(b cld_ops.Bundle, deps sui if err != nil { return sui_ops.OpTxResult[AcceptOwnershipLockReleaseTokenPoolObjects]{}, fmt.Errorf("failed to encode AcceptOwnership call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[AcceptOwnershipLockReleaseTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_lock_release_token_pool/op_execute_ownership_transfer_to_mcms.go b/deployment/ops/ccip_lock_release_token_pool/op_execute_ownership_transfer_to_mcms.go index 7d682246..9ac9fc48 100644 --- a/deployment/ops/ccip_lock_release_token_pool/op_execute_ownership_transfer_to_mcms.go +++ b/deployment/ops/ccip_lock_release_token_pool/op_execute_ownership_transfer_to_mcms.go @@ -43,7 +43,7 @@ var executeOwnershipTransferToMcmsLockReleaseTokenPoolHandler = func(b cld_ops.B if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsLockReleaseTokenPoolObjects]{}, fmt.Errorf("failed to encode ExecuteOwnershipTransferToMcms call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsLockReleaseTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_lock_release_token_pool/op_lock_release_token_pool.go b/deployment/ops/ccip_lock_release_token_pool/op_lock_release_token_pool.go index c0b5c4cb..74723e8f 100644 --- a/deployment/ops/ccip_lock_release_token_pool/op_lock_release_token_pool.go +++ b/deployment/ops/ccip_lock_release_token_pool/op_lock_release_token_pool.go @@ -176,11 +176,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Lock remoteTokenAddressesBytes[i] = b32 } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.ApplyChainUpdates( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().ApplyChainUpdates( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -189,6 +185,30 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Lock remotePoolAddressesBytes, remoteTokenAddressesBytes, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyChainUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyChainUpdates on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleasePackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool apply chain updates: %w", err) } @@ -199,6 +219,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Lock Digest: tx.Digest, PackageId: input.LockReleasePackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -230,11 +251,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetChainRateLimiterConfigs( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetChainRateLimiterConfigs( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -247,6 +264,30 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i input.InboundCapacities, input.InboundRates, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetChainRateLimiterConfigs call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetChainRateLimiterConfigs on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleasePackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool set configs rate limiter: %w", err) } @@ -257,6 +298,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i Digest: tx.Digest, PackageId: input.LockReleasePackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -324,17 +366,37 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input L return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.AddRemotePool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().AddRemotePool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.RemoteChainSelector, []byte(input.RemotePoolAddress), ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode AddRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of AddRemotePool on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool add remote pool: %w", err) } @@ -345,6 +407,7 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input L Digest: tx.Digest, PackageId: input.LockReleaseTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -371,17 +434,37 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockRel return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetPool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetPool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.RefObjectId}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.CoinMetadataAddress, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetPool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetPool on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool set pool: %w", err) } @@ -392,6 +475,7 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockRel Digest: tx.Digest, PackageId: input.LockReleaseTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -401,3 +485,271 @@ var LockReleaseTokenPoolSetPoolOp = cld_ops.NewOperation( "Sets the pool in the token admin registry for the CCIP LockRelease Token Pool contract", setPoolHandler, ) + +// LRTP -- set_rebalancer +type LockReleaseTokenPoolSetRebalancerInput struct { + LockReleaseTokenPoolPackageId string + CoinObjectTypeArg string + StateObjectId string + OwnerCap string + Rebalancer string +} + +var setRebalancerHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockReleaseTokenPoolSetRebalancerInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_lock_release_token_pool.NewLockReleaseTokenPool(input.LockReleaseTokenPoolPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) + } + + encodedCall, err := contract.Encoder().SetRebalancer( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.OwnerCap}, + bind.Object{Id: input.StateObjectId}, + input.Rebalancer, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetRebalancer call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetRebalancer on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool set rebalancer: %w", err) + } + + b.Logger.Infow("SetRebalancer on LockReleaseTokenPool", "LockReleaseTokenPool PackageId:", input.LockReleaseTokenPoolPackageId, "Rebalancer:", input.Rebalancer) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var LockReleaseTokenPoolSetRebalancerOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "lock_release_token_pool", "set_rebalancer"), + semver.MustParse("0.1.0"), + "Sets the rebalancer in the CCIP LockRelease Token Pool contract", + setRebalancerHandler, +) + +// LRTP -- set_allowlist_enabled +type LockReleaseTokenPoolSetAllowlistEnabledInput struct { + LockReleaseTokenPoolPackageId string + CoinObjectTypeArg string + StateObjectId string + OwnerCap string + Enabled bool +} + +var setAllowlistEnabledHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockReleaseTokenPoolSetAllowlistEnabledInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_lock_release_token_pool.NewLockReleaseTokenPool(input.LockReleaseTokenPoolPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) + } + + encodedCall, err := contract.Encoder().SetAllowlistEnabled( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.Enabled, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetAllowlistEnabled call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetAllowlistEnabled on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool set allowlist enabled: %w", err) + } + + b.Logger.Infow("SetAllowlistEnabled on LockReleaseTokenPool", "LockReleaseTokenPool PackageId:", input.LockReleaseTokenPoolPackageId, "Enabled:", input.Enabled) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var LockReleaseTokenPoolSetAllowlistEnabledOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "lock_release_token_pool", "set_allowlist_enabled"), + semver.MustParse("0.1.0"), + "Sets allowlist enabled in the CCIP LockRelease Token Pool contract", + setAllowlistEnabledHandler, +) + +// LRTP -- apply_allowlist_updates +type LockReleaseTokenPoolApplyAllowlistUpdatesInput struct { + LockReleaseTokenPoolPackageId string + CoinObjectTypeArg string + StateObjectId string + OwnerCap string + Removes []string + Adds []string +} + +var applyAllowlistUpdatesHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockReleaseTokenPoolApplyAllowlistUpdatesInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_lock_release_token_pool.NewLockReleaseTokenPool(input.LockReleaseTokenPoolPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) + } + + encodedCall, err := contract.Encoder().ApplyAllowlistUpdates( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.Removes, + input.Adds, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyAllowlistUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyAllowlistUpdates on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool apply allowlist updates: %w", err) + } + + b.Logger.Infow("ApplyAllowlistUpdates on LockReleaseTokenPool", "LockReleaseTokenPool PackageId:", input.LockReleaseTokenPoolPackageId, "Removes:", len(input.Removes), "Adds:", len(input.Adds)) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var LockReleaseTokenPoolApplyAllowlistUpdatesOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "lock_release_token_pool", "apply_allowlist_updates"), + semver.MustParse("0.1.0"), + "Applies allowlist updates in the CCIP LockRelease Token Pool contract", + applyAllowlistUpdatesHandler, +) + +// LRTP -- remove_remote_pool +type LockReleaseTokenPoolRemoveRemotePoolInput struct { + LockReleaseTokenPoolPackageId string + CoinObjectTypeArg string + StateObjectId string + OwnerCap string + RemoteChainSelector uint64 + RemotePoolAddress string +} + +var removeRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input LockReleaseTokenPoolRemoveRemotePoolInput) (output sui_ops.OpTxResult[NoObjects], err error) { + contract, err := module_lock_release_token_pool.NewLockReleaseTokenPool(input.LockReleaseTokenPoolPackageId, deps.Client) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create lock release token pool contract: %w", err) + } + + encodedCall, err := contract.Encoder().RemoveRemotePool( + []string{input.CoinObjectTypeArg}, + bind.Object{Id: input.StateObjectId}, + bind.Object{Id: input.OwnerCap}, + input.RemoteChainSelector, + []byte(input.RemotePoolAddress), + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode RemoveRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of RemoveRemotePool on LockReleaseTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute lock release token pool remove remote pool: %w", err) + } + + b.Logger.Infow("RemoveRemotePool on LockReleaseTokenPool", "LockReleaseTokenPool PackageId:", input.LockReleaseTokenPoolPackageId, "Chain:", input.RemoteChainSelector) + + return sui_ops.OpTxResult[NoObjects]{ + Digest: tx.Digest, + PackageId: input.LockReleaseTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, err +} + +var LockReleaseTokenPoolRemoveRemotePoolOp = cld_ops.NewOperation( + sui_ops.NewSuiOperationName("ccip", "lock_release_token_pool", "remove_remote_pool"), + semver.MustParse("0.1.0"), + "Removes a remote pool in the CCIP LockRelease Token Pool contract", + removeRemotePoolHandler, +) diff --git a/deployment/ops/ccip_lock_release_token_pool/op_registry.go b/deployment/ops/ccip_lock_release_token_pool/op_registry.go new file mode 100644 index 00000000..dc9ce915 --- /dev/null +++ b/deployment/ops/ccip_lock_release_token_pool/op_registry.go @@ -0,0 +1,27 @@ +package lockreleasetokenpoolops + +import ( + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// Exports every operation available so they can be registered to be used in dynamic changesets +var AllOperationsLockReleaseTP = []cld_ops.Operation[any, any, any]{ + // Deployment Operations + *DeployCCIPLockReleaseTokenPoolOp.AsUntyped(), + *TransferOwnershipLockReleaseTokenPoolOp.AsUntyped(), + *AcceptOwnershipLockReleaseTokenPoolOp.AsUntyped(), + // Token Pool Operations + *LockReleaseTokenPoolInitializeOp.AsUntyped(), + *LockReleaseTokenPoolInitializeByCcipAdminOp.AsUntyped(), + *LockReleaseTokenPoolApplyChainUpdatesOp.AsUntyped(), + *LockReleaseTokenPoolSetChainRateLimiterOp.AsUntyped(), + *LockReleaseTokenPoolProviderLiquidityOp.AsUntyped(), + *LockReleaseTokenPoolAddRemotePoolOp.AsUntyped(), + *LockReleaseTokenPoolSetPoolOp.AsUntyped(), + *LockReleaseTokenPoolSetRebalancerOp.AsUntyped(), + *LockReleaseTokenPoolSetAllowlistEnabledOp.AsUntyped(), + *LockReleaseTokenPoolApplyAllowlistUpdatesOp.AsUntyped(), + *LockReleaseTokenPoolRemoveRemotePoolOp.AsUntyped(), + // MCMS Operations + *ExecuteOwnershipTransferToMcmsLockReleaseTokenPoolOp.AsUntyped(), +} diff --git a/deployment/ops/ccip_lock_release_token_pool/seq_deploy_and_init.go b/deployment/ops/ccip_lock_release_token_pool/seq_deploy_and_init.go index 45272111..dddfd291 100644 --- a/deployment/ops/ccip_lock_release_token_pool/seq_deploy_and_init.go +++ b/deployment/ops/ccip_lock_release_token_pool/seq_deploy_and_init.go @@ -111,6 +111,20 @@ var DeployAndInitLockReleaseTokenPoolSequence = cld_ops.NewSequence( return DeployLockReleaseTokenPoolOutput{}, err } + // transfer ownership to MCMS + _, err = cld_ops.ExecuteOperation( + env, + TransferOwnershipLockReleaseTokenPoolOp, + deps, + TransferOwnershipLockReleaseTokenPoolInput{ + LockReleaseTokenPoolPackageId: deployReport.Output.PackageId, + TypeArgs: []string{input.CoinObjectTypeArg}, + StateObjectId: initReport.Output.Objects.StateObjectId, + OwnerCapObjectId: initReport.Output.Objects.OwnerCapObjectId, + To: input.LockReleaseTokenPoolDeployInput.MCMSAddress, + }, + ) + return DeployLockReleaseTokenPoolOutput{ LockReleaseTPPackageID: deployReport.Output.PackageId, Objects: DeployLockReleaseTokenPoolObjects{ diff --git a/deployment/ops/ccip_managed_token_pool/op_deploy.go b/deployment/ops/ccip_managed_token_pool/op_deploy.go index 1536776c..9210cadd 100644 --- a/deployment/ops/ccip_managed_token_pool/op_deploy.go +++ b/deployment/ops/ccip_managed_token_pool/op_deploy.go @@ -120,7 +120,7 @@ var acceptOwnershipManagedTokenPoolHandler = func(b cld_ops.Bundle, deps sui_ops if err != nil { return sui_ops.OpTxResult[AcceptOwnershipManagedTokenPoolObjects]{}, fmt.Errorf("failed to encode AcceptOwnership call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[AcceptOwnershipManagedTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_managed_token_pool/op_managed_token_pool.go b/deployment/ops/ccip_managed_token_pool/op_managed_token_pool.go index a81a634c..b983c39c 100644 --- a/deployment/ops/ccip_managed_token_pool/op_managed_token_pool.go +++ b/deployment/ops/ccip_managed_token_pool/op_managed_token_pool.go @@ -180,11 +180,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Mana remoteTokenAddressesBytes[i] = b32 } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.ApplyChainUpdates( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().ApplyChainUpdates( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -193,6 +189,30 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Mana remotePoolAddressesBytes, remoteTokenAddressesBytes, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyChainUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyChainUpdates on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool apply chain updates: %w", err) } @@ -203,6 +223,7 @@ var applyChainUpdates = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Mana Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -229,17 +250,37 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input M return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.AddRemotePool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().AddRemotePool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.RemoteChainSelector, []byte(input.RemotePoolAddress), ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode AddRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of AddRemotePool on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool add remote pool: %w", err) } @@ -250,6 +291,7 @@ var addRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input M Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -276,17 +318,37 @@ var removeRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, inpu return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.RemoveRemotePool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().RemoveRemotePool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.RemoteChainSelector, []byte(input.RemotePoolAddress), ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode RemoveRemotePool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of RemoveRemotePool on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool remove remote pool: %w", err) } @@ -297,6 +359,7 @@ var removeRemotePoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, inpu Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -328,11 +391,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetChainRateLimiterConfigs( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetChainRateLimiterConfigs( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, @@ -345,6 +404,30 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i input.InboundCapacities, input.InboundRates, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetChainRateLimiterConfigs call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetChainRateLimiterConfigs on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool set configs rate limiter: %w", err) } @@ -355,6 +438,7 @@ var setChainRateLimiterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -380,16 +464,36 @@ var setAllowlistEnabledHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetAllowlistEnabled( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetAllowlistEnabled( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.Enabled, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetAllowlistEnabled call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetAllowlistEnabled on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool set allowlist enabled: %w", err) } @@ -400,6 +504,7 @@ var setAllowlistEnabledHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, i Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -426,17 +531,37 @@ var applyAllowlistUpdatesHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.ApplyAllowlistUpdates( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().ApplyAllowlistUpdates( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCap}, input.Removes, input.Adds, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode ApplyAllowlistUpdates call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of ApplyAllowlistUpdates on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool apply allowlist updates: %w", err) } @@ -447,6 +572,7 @@ var applyAllowlistUpdatesHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } @@ -474,11 +600,7 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Managed return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token pool contract: %w", err) } - opts := deps.GetCallOpts() - opts.Signer = deps.Signer - tx, err := contract.SetPool( - b.GetContext(), - opts, + encodedCall, err := contract.Encoder().SetPool( []string{input.CoinObjectTypeArg}, bind.Object{Id: input.RefObjectId}, bind.Object{Id: input.StateObjectId}, @@ -486,6 +608,30 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Managed input.CoinMetadataAddress, input.ManagedTokenState, ) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to encode SetPool call: %w", err) + } + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, []string{input.CoinObjectTypeArg}) + if err != nil { + return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) + } + if deps.Signer == nil { + b.Logger.Infow("Skipping execution of SetPool on ManagedTokenPool as per no Signer provided") + return sui_ops.OpTxResult[NoObjects]{ + Digest: "", + PackageId: input.ManagedTokenPoolPackageId, + Objects: NoObjects{}, + Call: call, + }, nil + } + + opts := deps.GetCallOpts() + opts.Signer = deps.Signer + tx, err := contract.Bound().ExecuteTransaction( + b.GetContext(), + opts, + encodedCall, + ) if err != nil { return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token pool set pool: %w", err) } @@ -496,6 +642,7 @@ var setPoolHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input Managed Digest: tx.Digest, PackageId: input.ManagedTokenPoolPackageId, Objects: NoObjects{}, + Call: call, }, err } diff --git a/deployment/ops/ccip_managed_token_pool/op_registry.go b/deployment/ops/ccip_managed_token_pool/op_registry.go new file mode 100644 index 00000000..1e4ae905 --- /dev/null +++ b/deployment/ops/ccip_managed_token_pool/op_registry.go @@ -0,0 +1,22 @@ +package managedtokenpoolops + +import ( + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// Exports every operation available so they can be registered to be used in dynamic changesets +var AllOperationsManagedTP = []cld_ops.Operation[any, any, any]{ + *AcceptOwnershipManagedTokenPoolOp.AsUntyped(), + *ExecuteOwnershipTransferToMcmsManagedTokenPoolOp.AsUntyped(), + *DeployCCIPManagedTokenPoolOp.AsUntyped(), + *ManagedTokenPoolInitializeOp.AsUntyped(), + *ManagedTokenPoolAddRemotePoolOp.AsUntyped(), + *ManagedTokenPoolInitializeByCcipAdminOp.AsUntyped(), + *ManagedTokenPoolApplyChainUpdatesOp.AsUntyped(), + *ManagedTokenPoolAddRemotePoolOp.AsUntyped(), + *ManagedTokenPoolRemoveRemotePoolOp.AsUntyped(), + *ManagedTokenPoolSetChainRateLimiterOp.AsUntyped(), + *ManagedTokenPoolSetAllowlistEnabledOp.AsUntyped(), + *ManagedTokenPoolApplyAllowlistUpdatesOp.AsUntyped(), + *ManagedTokenPoolSetPoolOp.AsUntyped(), +} diff --git a/deployment/ops/ccip_managed_token_pool/seq_deploy_and_init.go b/deployment/ops/ccip_managed_token_pool/seq_deploy_and_init.go index 5f9f5fe4..c072ad92 100644 --- a/deployment/ops/ccip_managed_token_pool/seq_deploy_and_init.go +++ b/deployment/ops/ccip_managed_token_pool/seq_deploy_and_init.go @@ -122,6 +122,23 @@ var DeployAndInitManagedTokenPoolSequence = cld_ops.NewSequence( return DeployManagedTokenPoolOutput{}, err } + // init ownership transfer to MCMS + _, err = cld_ops.ExecuteOperation( + env, + TransferOwnershipManagedTokenPoolOp, + deps, + TransferOwnershipManagedTokenPoolInput{ + ManagedTokenPoolPackageId: deployReport.Output.PackageId, + TypeArgs: []string{input.CoinObjectTypeArg}, + StateObjectId: initReport.Output.Objects.StateObjectId, + OwnerCapObjectId: initReport.Output.Objects.OwnerCapObjectId, + To: input.MCMSAddress, + }, + ) + if err != nil { + return DeployManagedTokenPoolOutput{}, err + } + return DeployManagedTokenPoolOutput{ ManagedTPPackageId: deployReport.Output.PackageId, Objects: DeployManagedTokenPoolObjects{ diff --git a/deployment/ops/ccip_token_pool/seq_deploy_and_init_all.go b/deployment/ops/ccip_token_pool/seq_deploy_and_init_all.go new file mode 100644 index 00000000..b4c54d05 --- /dev/null +++ b/deployment/ops/ccip_token_pool/seq_deploy_and_init_all.go @@ -0,0 +1,77 @@ +package tokenpoolops + +import ( + "fmt" + + "github.com/Masterminds/semver/v3" + + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + sui_ops "github.com/smartcontractkit/chainlink-sui/deployment/ops" + burnminttokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_burn_mint_token_pool" + lockreleasetokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_lock_release_token_pool" + managedtokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_managed_token_pool" +) + +// DeployAndInitAllTokenPoolsInput contains configuration for all supported token pool types. +// This replicates the logic from the DeployTPAndConfigure changeset, allowing deployment +// of multiple token pool types in a single sequence operation. +type DeployAndInitAllTokenPoolsInput struct { + // Common configuration + SuiChainSelector uint64 + TokenPoolTypes []string // supported: "bnm", "lnr", "managed" + + // Token pool specific inputs + ManagedTPInput managedtokenpoolops.SeqDeployAndInitManagedTokenPoolInput + LockReleaseTPInput lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolInput + BurnMintTpInput burnminttokenpoolops.DeployAndInitBurnMintTokenPoolInput +} + +// DeployAndInitAllTokenPoolsOutput contains results for all deployed token pools +type DeployAndInitAllTokenPoolsOutput struct { + burnminttokenpoolops.DeployBurnMintTokenPoolOutput + lockreleasetokenpoolops.DeployLockReleaseTokenPoolOutput + managedtokenpoolops.DeployManagedTokenPoolOutput +} + +// DeployAndInitAllTokenPoolsSequence provides a unified sequence for deploying and +// initializing multiple token pool types. This sequence replicates the core logic +// of the DeployTPAndConfigure changeset by conditionally deploying burn mint, +// lock release, and managed token pools based on the provided configuration. +var DeployAndInitAllTokenPoolsSequence = cld_ops.NewSequence( + "sui-deploy-and-init-all-token-pools-seq", + semver.MustParse("0.1.0"), + "Deploys and initializes multiple token pool types based on configuration", + func(env cld_ops.Bundle, deps sui_ops.OpTxDeps, input DeployAndInitAllTokenPoolsInput) (DeployAndInitAllTokenPoolsOutput, error) { + output := DeployAndInitAllTokenPoolsOutput{} + for _, tokenPoolType := range input.TokenPoolTypes { + switch tokenPoolType { + case "bnm": + burnMintReport, err := cld_ops.ExecuteSequence(env, burnminttokenpoolops.DeployAndInitBurnMintTokenPoolSequence, deps, input.BurnMintTpInput) + if err != nil { + return DeployAndInitAllTokenPoolsOutput{}, fmt.Errorf("failed to deploy burn mint token pool: %w", err) + } + output.DeployBurnMintTokenPoolOutput = burnMintReport.Output + + case "lnr": + lockReleaseReport, err := cld_ops.ExecuteSequence(env, lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolSequence, deps, input.LockReleaseTPInput) + if err != nil { + return DeployAndInitAllTokenPoolsOutput{}, fmt.Errorf("failed to deploy lock release token pool: %w", err) + } + output.DeployLockReleaseTokenPoolOutput = lockReleaseReport.Output + + case "managed": + managedReport, err := cld_ops.ExecuteSequence(env, managedtokenpoolops.DeployAndInitManagedTokenPoolSequence, deps, input.ManagedTPInput) + if err != nil { + return DeployAndInitAllTokenPoolsOutput{}, fmt.Errorf("failed to deploy managed token pool: %w", err) + } + output.DeployManagedTokenPoolOutput = managedReport.Output + + default: + return DeployAndInitAllTokenPoolsOutput{}, fmt.Errorf("unsupported token pool type: %s", tokenPoolType) + } + } + + return output, nil + }, +) diff --git a/deployment/ops/ccip_usdc_token_pool/op_deploy.go b/deployment/ops/ccip_usdc_token_pool/op_deploy.go index 317e3544..f8f5327b 100644 --- a/deployment/ops/ccip_usdc_token_pool/op_deploy.go +++ b/deployment/ops/ccip_usdc_token_pool/op_deploy.go @@ -130,7 +130,7 @@ var acceptOwnershipUsdcTokenPoolHandler = func(b cld_ops.Bundle, deps sui_ops.Op if err != nil { return sui_ops.OpTxResult[AcceptOwnershipUsdcTokenPoolObjects]{}, fmt.Errorf("failed to encode AcceptOwnership call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[AcceptOwnershipUsdcTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/ccip_usdc_token_pool/op_execute_ownership_transfer_to_mcms.go b/deployment/ops/ccip_usdc_token_pool/op_execute_ownership_transfer_to_mcms.go index b908171b..56580703 100644 --- a/deployment/ops/ccip_usdc_token_pool/op_execute_ownership_transfer_to_mcms.go +++ b/deployment/ops/ccip_usdc_token_pool/op_execute_ownership_transfer_to_mcms.go @@ -43,7 +43,7 @@ var executeOwnershipTransferToMcmsUsdcTokenPoolHandler = func(b cld_ops.Bundle, if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsUsdcTokenPoolObjects]{}, fmt.Errorf("failed to encode ExecuteOwnershipTransferToMcms call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsUsdcTokenPoolObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/managed_token/op_deploy.go b/deployment/ops/managed_token/op_deploy.go index bcef650e..726fdce5 100644 --- a/deployment/ops/managed_token/op_deploy.go +++ b/deployment/ops/managed_token/op_deploy.go @@ -116,7 +116,7 @@ var acceptOwnershipManagedTokenHandler = func(b cld_ops.Bundle, deps sui_ops.OpT if err != nil { return sui_ops.OpTxResult[AcceptOwnershipManagedTokenObjects]{}, fmt.Errorf("failed to encode AcceptOwnership call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[AcceptOwnershipManagedTokenObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/managed_token/op_execute_ownership_transfer_to_mcms.go b/deployment/ops/managed_token/op_execute_ownership_transfer_to_mcms.go index e1ad4ef6..384749ad 100644 --- a/deployment/ops/managed_token/op_execute_ownership_transfer_to_mcms.go +++ b/deployment/ops/managed_token/op_execute_ownership_transfer_to_mcms.go @@ -43,7 +43,7 @@ var executeOwnershipTransferToMcmsManagedTokenHandler = func(b cld_ops.Bundle, d if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsManagedTokenObjects]{}, fmt.Errorf("failed to encode ExecuteOwnershipTransferToMcms call: %w", err) } - call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId) + call, err := sui_ops.ToTransactionCallWithTypeArgs(encodedCall, input.StateObjectId, input.TypeArgs) if err != nil { return sui_ops.OpTxResult[ExecuteOwnershipTransferToMcmsManagedTokenObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err) } diff --git a/deployment/ops/managed_token/op_managed_token.go b/deployment/ops/managed_token/op_managed_token.go index f2149d9e..0b550877 100644 --- a/deployment/ops/managed_token/op_managed_token.go +++ b/deployment/ops/managed_token/op_managed_token.go @@ -83,7 +83,10 @@ var ManagedTokenInitializeOp = cld_ops.NewOperation( ) // MANAGED_TOKEN -- configure_new_minter -type NoObjects struct { + +type NoObjects struct{} +type ConfigureMinterObjects struct { + MinterCapObjectId string } type ManagedTokenConfigureNewMinterInput struct { @@ -96,15 +99,15 @@ type ManagedTokenConfigureNewMinterInput struct { IsUnlimited bool } -var configureNewMinterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input ManagedTokenConfigureNewMinterInput) (output sui_ops.OpTxResult[NoObjects], err error) { +var configureNewMinterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input ManagedTokenConfigureNewMinterInput) (output sui_ops.OpTxResult[ConfigureMinterObjects], err error) { contract, err := module_managed_token.NewManagedToken(input.ManagedTokenPackageId, deps.Client) if err != nil { - return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to create managed token contract: %w", err) + return sui_ops.OpTxResult[ConfigureMinterObjects]{}, fmt.Errorf("failed to create managed token contract: %w", err) } opts := deps.GetCallOpts() opts.Signer = deps.Signer - _, err = contract.ConfigureNewMinter( + tx, err := contract.ConfigureNewMinter( b.GetContext(), opts, []string{input.CoinObjectTypeArg}, @@ -115,15 +118,22 @@ var configureNewMinterHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, in input.IsUnlimited, ) if err != nil { - return sui_ops.OpTxResult[NoObjects]{}, fmt.Errorf("failed to execute managed token configure new minter: %w", err) + return sui_ops.OpTxResult[ConfigureMinterObjects]{}, fmt.Errorf("failed to execute managed token configure new minter: %w", err) + } + + obj1, err1 := bind.FindObjectIdFromPublishTx(*tx, "managed_token", "MintCap") + if err1 != nil { + return sui_ops.OpTxResult[ConfigureMinterObjects]{}, fmt.Errorf("failed to find MintCap object ID in tx: %w", err1) } b.Logger.Infow("ConfigureNewMinter on ManagedToken", "ManagedToken PackageId:", input.ManagedTokenPackageId, "Minter:", input.MinterAddress) - return sui_ops.OpTxResult[NoObjects]{ + return sui_ops.OpTxResult[ConfigureMinterObjects]{ Digest: "", // tx.Digest when available PackageId: input.ManagedTokenPackageId, - Objects: NoObjects{}, + Objects: ConfigureMinterObjects{ + MinterCapObjectId: obj1, + }, }, err } diff --git a/deployment/ops/managed_token/seq_deploy_and_init.go b/deployment/ops/managed_token/seq_deploy_and_init.go index 20b24c39..44d51392 100644 --- a/deployment/ops/managed_token/seq_deploy_and_init.go +++ b/deployment/ops/managed_token/seq_deploy_and_init.go @@ -9,8 +9,9 @@ import ( ) type DeployManagedTokenObjects struct { - OwnerCapObjectId string - StateObjectId string + OwnerCapObjectId string + StateObjectId string + MinterCapObjectId string } type DeployManagedTokenOutput struct { @@ -55,9 +56,10 @@ var DeployAndInitManagedTokenSequence = cld_ops.NewSequence( return DeployManagedTokenOutput{}, err } + minterObjectId := "" // Configure a new minter if specified if input.MinterAddress != "" { - _, err = cld_ops.ExecuteOperation( + minterReport, err := cld_ops.ExecuteOperation( env, ManagedTokenConfigureNewMinterOp, deps, @@ -74,13 +76,17 @@ var DeployAndInitManagedTokenSequence = cld_ops.NewSequence( if err != nil { return DeployManagedTokenOutput{}, err } + + minterObjectId = minterReport.Output.Objects.MinterCapObjectId + } return DeployManagedTokenOutput{ ManagedTokenPackageId: deployReport.Output.PackageId, Objects: DeployManagedTokenObjects{ - OwnerCapObjectId: initReport.Output.Objects.OwnerCapObjectId, - StateObjectId: initReport.Output.Objects.StateObjectId, + OwnerCapObjectId: initReport.Output.Objects.OwnerCapObjectId, + StateObjectId: initReport.Output.Objects.StateObjectId, + MinterCapObjectId: minterObjectId, }, }, nil }, diff --git a/deployment/ops/mcms/op_proposal_generate.go b/deployment/ops/mcms/op_proposal_generate.go index 4c6bf060..e8e65709 100644 --- a/deployment/ops/mcms/op_proposal_generate.go +++ b/deployment/ops/mcms/op_proposal_generate.go @@ -97,6 +97,7 @@ var generateProposalHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, inpu call.Module, []string{}, call.StateObjID, + call.TypeArgs, ) mcmsTxs[i] = tx } diff --git a/deployment/ops/ownership/seq_accept_ccip_ownership.go b/deployment/ops/ownership/seq_accept_ccip_ownership.go index 717b644b..3309ab3d 100644 --- a/deployment/ops/ownership/seq_accept_ccip_ownership.go +++ b/deployment/ops/ownership/seq_accept_ccip_ownership.go @@ -1,9 +1,6 @@ package ownershipops import ( - "encoding/json" - "fmt" - "github.com/Masterminds/semver/v3" "github.com/smartcontractkit/chainlink-deployments-framework/operations" @@ -94,9 +91,6 @@ var AcceptCCIPOwnershipSeq = cld_ops.NewSequence( ChainSelector: input.ChainSelector, } - jsonbytes, _ := json.MarshalIndent(proposalInput, "", " ") - fmt.Println("Accept CCIP Ownership Proposal Input: ", string(jsonbytes)) - acceptOwnershipProposalReport, err := cld_ops.ExecuteSequence(env, mcmsops.MCMSDynamicProposalGenerateSeq, deps, proposalInput) if err != nil { return mcms.TimelockProposal{}, err diff --git a/deployment/ops/registry/op_registry.go b/deployment/ops/registry/op_registry.go index 33658e4a..b3345e86 100644 --- a/deployment/ops/registry/op_registry.go +++ b/deployment/ops/registry/op_registry.go @@ -3,6 +3,9 @@ package opregistry import ( cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" ccipops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip" + burnminttokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_burn_mint_token_pool" + lockreleasetokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_lock_release_token_pool" + managedtokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_managed_token_pool" offrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_offramp" onrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_onramp" routerops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_router" @@ -22,7 +25,10 @@ var AllOperations = func() []cld_ops.Operation[any, any, any] { // MCMS Operations operations = append(operations, mcmsops.AllOperationsMCMS...) - operations = append(operations, *mcmsops.AddModulesMCMSOp.AsUntyped()) + // TP Operations + operations = append(operations, lockreleasetokenpoolops.AllOperationsLockReleaseTP...) + operations = append(operations, burnminttokenpoolops.AllOperationsBurnMintTP...) + operations = append(operations, managedtokenpoolops.AllOperationsManagedTP...) // Add more operation slices here as needed: // operations = append(operations, anotherops.AllOperations...) diff --git a/deployment/ops/types.go b/deployment/ops/types.go index 1eb65890..c4888253 100644 --- a/deployment/ops/types.go +++ b/deployment/ops/types.go @@ -56,7 +56,27 @@ func ToTransactionCall(call *bind.EncodedCall, stateObjID string) (TransactionCa Module: call.Module.ModuleName, Function: call.Function, Data: calldata, - TypeArgs: call.TypeParams, + TypeArgs: []string{}, + StateObjID: stateObjID, + }, nil +} + +func ToTransactionCallWithTypeArgs(call *bind.EncodedCall, stateObjID string, typeArgs []string) (TransactionCall, error) { + if call == nil { + return TransactionCall{}, fmt.Errorf("nil call provided") + } + + calldata, err := extractByteArgsFromEncodedCall(*call) + if err != nil { + return TransactionCall{}, fmt.Errorf("failed to extract byte args from encoded call: %w", err) + } + + return TransactionCall{ + PackageID: call.Module.PackageID, + Module: call.Module.ModuleName, + Function: call.Function, + Data: calldata, + TypeArgs: typeArgs, StateObjID: stateObjID, }, nil } diff --git a/deployment/types.go b/deployment/types.go index 72ae2199..2f72a01d 100644 --- a/deployment/types.go +++ b/deployment/types.go @@ -42,9 +42,27 @@ var ( SuiLinkTokenTreasuryCapID deployment.ContractType = "SuiLinkTokenTreasuryCapID" SuiMCMSType deployment.ContractType = "SuiManyChainMultisig" SuiLinkTokenType deployment.ContractType = "SuiLinkToken" - SuiBnMTokenPoolType deployment.ContractType = "SuiBnMTokenPool" - SuiBnMTokenPoolStateType deployment.ContractType = "SuiBnMTokenPoolState" - SuiBnMTokenPoolOwnerIDType deployment.ContractType = "SuiBnMTokenPoolOwnerID" + + // Managed Token related + SuiManagedTokenType deployment.ContractType = "SuiManagedToken" + SuiManagedTokenOwnerCapObjectID deployment.ContractType = "SuiManagedTokenOwnerCapObjectID" + SuiManagedTokenStateObjectID deployment.ContractType = "SuiManagedTokenStateObjectID" + SuiManagedTokenMinterCapID deployment.ContractType = "SuiManagedTokenMinterCapID" + + // BnM Token Pool related + SuiBnMTokenPoolType deployment.ContractType = "SuiBnMTokenPool" + SuiBnMTokenPoolStateType deployment.ContractType = "SuiBnMTokenPoolState" + SuiBnMTokenPoolOwnerIDType deployment.ContractType = "SuiBnMTokenPoolOwnerID" + + // LnR Token Pool related + SuiLnRTokenPoolType deployment.ContractType = "SuiLnRTokenPool" + SuiLnRTokenPoolStateType deployment.ContractType = "SuiLnRTokenPoolState" + SuiLnRTokenPoolOwnerIDType deployment.ContractType = "SuiLnRTokenPoolOwnerID" + + // Managed Token Pool related + SuiManagedTokenPoolType deployment.ContractType = "SuiManagedTokenPool" + SuiManagedTokenPoolStateType deployment.ContractType = "SuiManagedTokenPoolState" + SuiManagedTokenPoolOwnerIDType deployment.ContractType = "SuiManagedTokenPoolOwnerID" ) var ( diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 5c732063..e17e8d8e 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -12,7 +12,7 @@ require ( github.com/smartcontractkit/chainlink-deployments-framework v0.47.0 github.com/smartcontractkit/chainlink-sui v0.0.0-20251016153021-3d4a0208cf70 github.com/smartcontractkit/chainlink-sui/deployment v0.0.0-20250903045200-c3d973201e55 - github.com/smartcontractkit/mcms v0.28.0 + github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef github.com/stretchr/testify v1.10.0 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 2cdffa33..fa2eac86 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -635,8 +635,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20250905115425-2785a5cee79d h1:/0/80Ic6wpKH5F1nwDoRj9+70IxXunvCyNcCkA+9ik0= github.com/smartcontractkit/libocr v0.0.0-20250905115425-2785a5cee79d/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= -github.com/smartcontractkit/mcms v0.28.0 h1:N/zUNRZixSbas7EQ9yk2ksmb9b5M734Tu8pY3F+ErJ4= -github.com/smartcontractkit/mcms v0.28.0/go.mod h1:SYQok8vhBAc9ZdlJ+TKQpJlIQAHcP83KC4fKIBm/j7I= +github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef h1:jgoBu/KzwMsrx1c29DQPD/G7aoGQMch83hRSABbSkF0= +github.com/smartcontractkit/mcms v0.28.1-0.20251022150312-a7ac4a4da5ef/go.mod h1:SYQok8vhBAc9ZdlJ+TKQpJlIQAHcP83KC4fKIBm/j7I= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= diff --git a/integration-tests/mcms/common.go b/integration-tests/mcms/common.go index 31b1a4d5..ee1faca3 100644 --- a/integration-tests/mcms/common.go +++ b/integration-tests/mcms/common.go @@ -4,6 +4,7 @@ package mcms import ( "crypto/ecdsa" + "encoding/hex" "slices" "time" @@ -14,6 +15,12 @@ import ( mcmsencoder "github.com/smartcontractkit/chainlink-sui/bindings" "github.com/smartcontractkit/chainlink-sui/bindings/bind" "github.com/smartcontractkit/chainlink-sui/bindings/tests/testenv" + "github.com/smartcontractkit/chainlink-sui/deployment" + ccipops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip" + offrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_offramp" + onrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_onramp" + routerops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_router" + linkops "github.com/smartcontractkit/chainlink-sui/deployment/ops/link" mcmsops "github.com/smartcontractkit/chainlink-sui/deployment/ops/mcms" "github.com/smartcontractkit/mcms" "github.com/smartcontractkit/mcms/sdk" @@ -23,6 +30,7 @@ import ( "github.com/stretchr/testify/suite" cselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" sui_ops "github.com/smartcontractkit/chainlink-sui/deployment/ops" opregistry "github.com/smartcontractkit/chainlink-sui/deployment/ops/registry" @@ -85,15 +93,37 @@ type MCMSTestSuite struct { // Ops deps sui_ops.OpTxDeps bundle cld_ops.Bundle + + // CCIP + // LINK + linkPackageId string + linkObjects linkops.DeployLinkObjects + + // CCIP + ccipPackageId string + ccipObjects ccipops.DeployCCIPSeqObjects + + // Router + ccipRouterPackageId string + ccipRouterObjects routerops.DeployCCIPRouterObjects + + // Onramp + ccipOnrampPackageId string + ccipOnrampObjects onrampops.DeployCCIPOnRampSeqObjects + + // offramp + ccipOfframpPackageId string + ccipOfframpObjects offrampops.DeployCCIPOffRampSeqObjects } +// TODO: refactor so suites are per product func (s *MCMSTestSuite) SetupSuite() { signer, client := testenv.SetupEnvironment(s.T()) deps := sui_ops.OpTxDeps{ Client: client, Signer: signer, GetCallOpts: func() *bind.CallOpts { - b := uint64(500_000_000) // needs to be high for publishing + b := uint64(10_000_000_000) // needs to be high for publishing and big proposals return &bind.CallOpts{ WaitForExecution: true, GasBudget: &b, @@ -169,6 +199,149 @@ func (s *MCMSTestSuite) SetupSuite() { }) s.Require().NoError(err, "executing ownership transfer to self") s.T().Logf("✅ Transferred ownership of MCMS to itself in tx: %s", rep.Output.Digest) + + s.SetupCCIP() +} + +func (s *MCMSTestSuite) SetupCCIP() { + // Deploy LINK + linkReport, err := cld_ops.ExecuteOperation(s.bundle, linkops.DeployLINKOp, s.deps, cld_ops.EmptyInput{}) + require.NoError(s.T(), err, "failed to deploy LINK token") + s.linkPackageId = linkReport.Output.PackageId + s.linkObjects = linkReport.Output.Objects + + configDigestHex := "e3b1c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + configDigest, err := hex.DecodeString(configDigestHex) + require.NoError(s.T(), err, "failed to decode config digest") + + publicKey1Hex := "8a1b2c3d4e5f60718293a4b5c6d7e8f901234567" + publicKey1, err := hex.DecodeString(publicKey1Hex) + require.NoError(s.T(), err, "failed to decode public key 1") + + publicKey2Hex := "7b8c9dab0c1d2e3f405162738495a6b7c8d9e0f1" + publicKey2, err := hex.DecodeString(publicKey2Hex) + require.NoError(s.T(), err, "failed to decode public key 2") + + publicKey3Hex := "1234567890abcdef1234567890abcdef12345678" + publicKey3, err := hex.DecodeString(publicKey3Hex) + require.NoError(s.T(), err, "failed to decode public key 3") + + publicKey4Hex := "90abcdef1234567890abcdef1234567890abcdef" + publicKey4, err := hex.DecodeString(publicKey4Hex) + require.NoError(s.T(), err, "failed to decode public key 4") + + // Use the same seq as in production deployment + ccipReport, err := cld_ops.ExecuteSequence(s.bundle, ccipops.DeployAndInitCCIPSequence, s.deps, ccipops.DeployAndInitCCIPSeqInput{ + LinkTokenCoinMetadataObjectId: linkReport.Output.Objects.CoinMetadataObjectId, + LocalChainSelector: 1, + DestChainSelector: 2, + DeployCCIPInput: ccipops.DeployCCIPInput{ + McmsPackageId: s.mcmsPackageID, + McmsOwner: s.mcmsOwnerAddress, + }, + MaxFeeJuelsPerMsg: "100000000", + TokenPriceStalenessThreshold: 60, + // Fee Quoter configuration + AddMinFeeUsdCents: []uint32{3000}, + AddMaxFeeUsdCents: []uint32{30000}, + AddDeciBps: []uint16{1000}, + AddDestGasOverhead: []uint32{1000000}, + AddDestBytesOverhead: []uint32{1000}, + AddIsEnabled: []bool{true}, + RemoveTokens: []string{}, + // Fee Quoter destination chain configuration + IsEnabled: true, + MaxNumberOfTokensPerMsg: 2, + MaxDataBytes: 2000, + MaxPerMsgGasLimit: 5000000, + DestGasOverhead: 1000000, + DestGasPerPayloadByteBase: byte(2), + DestGasPerPayloadByteHigh: byte(5), + DestGasPerPayloadByteThreshold: uint16(10), + DestDataAvailabilityOverheadGas: 300000, + DestGasPerDataAvailabilityByte: 4, + DestDataAvailabilityMultiplierBps: 1, + ChainFamilySelector: []byte{0x28, 0x12, 0xd5, 0x2c}, + EnforceOutOfOrder: false, + DefaultTokenFeeUsdCents: 3, + DefaultTokenDestGasOverhead: 100000, + DefaultTxGasLimit: 500000, + GasMultiplierWeiPerEth: 100, + GasPriceStalenessThreshold: 1000000000, + NetworkFeeUsdCents: 10, + // Premium multiplier updates + PremiumMultiplierWeiPerEth: []uint64{10}, + + RmnHomeContractConfigDigest: configDigest, + SignerOnchainPublicKeys: [][]byte{publicKey1, publicKey2, publicKey3, publicKey4}, + NodeIndexes: []uint64{0, 1, 2, 3}, + FSign: uint64(1), + }) + require.NoError(s.T(), err, "failed to execute CCIP deploy sequence") + require.NotEmpty(s.T(), ccipReport.Output.CCIPPackageId, "CCIP package ID should not be empty") + + s.linkObjects = linkReport.Output.Objects + s.ccipPackageId = ccipReport.Output.CCIPPackageId + s.ccipObjects = ccipReport.Output.Objects + + // Deploy Router + routerReport, err := cld_ops.ExecuteOperation(s.bundle, routerops.DeployCCIPRouterOp, s.deps, routerops.DeployCCIPRouterInput{ + McmsPackageId: s.mcmsPackageID, + McmsOwner: s.mcmsOwnerAddress, + }) + require.NoError(s.T(), err, "failed to execute CCIP deploy sequence") + + s.ccipRouterPackageId = routerReport.Output.PackageId + s.ccipRouterObjects = routerReport.Output.Objects + + // Deploy Onramp + ccipOnRampSeqInput := deployment.DefaultOnRampSeqConfig + ccipOnRampSeqInput.DeployCCIPOnRampInput.CCIPPackageId = ccipReport.Output.CCIPPackageId + ccipOnRampSeqInput.DeployCCIPOnRampInput.MCMSPackageId = s.mcmsPackageID + ccipOnRampSeqInput.DeployCCIPOnRampInput.MCMSOwnerPackageId = s.mcmsOwnerAddress + ccipOnRampSeqInput.OnRampInitializeInput.NonceManagerCapId = ccipReport.Output.Objects.NonceManagerCapObjectId + ccipOnRampSeqInput.OnRampInitializeInput.SourceTransferCapId = ccipReport.Output.Objects.SourceTransferCapObjectId + ccipOnRampSeqInput.OnRampInitializeInput.ChainSelector = uint64(s.chainSelector) + ccipOnRampSeqInput.OnRampInitializeInput.FeeAggregator = s.mcmsOwnerAddress + ccipOnRampSeqInput.OnRampInitializeInput.AllowListAdmin = s.mcmsOwnerAddress + ccipOnRampSeqInput.OnRampInitializeInput.DestChainSelectors = []uint64{cselectors.ETHEREUM_MAINNET.Selector} + ccipOnRampSeqInput.OnRampInitializeInput.DestChainRouters = []string{routerReport.Output.PackageId} + ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.DestChainSelector = []uint64{cselectors.ETHEREUM_MAINNET.Selector} + ccipOnRampSeqInput.ApplyAllowListUpdatesInput.DestChainSelector = []uint64{cselectors.ETHEREUM_MAINNET.Selector} + ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.DestChainRouters = []string{routerReport.Output.PackageId} + ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.CCIPObjectRefId = ccipReport.Output.Objects.CCIPObjectRefObjectId + + ccipOnRampSeqReport, err := operations.ExecuteSequence(s.bundle, onrampops.DeployAndInitCCIPOnRampSequence, s.deps, ccipOnRampSeqInput) + require.NoError(s.T(), err, "failed to execute CCIP OnRamp deploy sequence") + + s.ccipOnrampPackageId = ccipOnRampSeqReport.Output.CCIPOnRampPackageId + s.ccipOnrampObjects = ccipOnRampSeqReport.Output.Objects + + // Deploy offramp + ccipOffRampSeqInput := deployment.DefaultOffRampSeqConfig + // note: this is a regression, can't acess other chains state very cleanly + onRampBytes := [][]byte{ + {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + } + + // Inject dynamic values for deployment + ccipOffRampSeqInput.CCIPObjectRefId = ccipReport.Output.Objects.CCIPObjectRefObjectId + ccipOffRampSeqInput.DeployCCIPOffRampInput.CCIPPackageId = ccipReport.Output.CCIPPackageId + ccipOffRampSeqInput.DeployCCIPOffRampInput.MCMSPackageId = s.mcmsPackageID + + ccipOffRampSeqInput.InitializeOffRampInput.DestTransferCapId = ccipReport.Output.Objects.DestTransferCapObjectId + ccipOffRampSeqInput.InitializeOffRampInput.FeeQuoterCapId = ccipReport.Output.Objects.FeeQuoterCapObjectId + ccipOffRampSeqInput.InitializeOffRampInput.ChainSelector = uint64(s.chainSelector) + ccipOffRampSeqInput.InitializeOffRampInput.SourceChainSelectors = []uint64{ + cselectors.ETHEREUM_MAINNET.Selector, + } + ccipOffRampSeqInput.InitializeOffRampInput.SourceChainsOnRamp = onRampBytes + + ccipOffRampSeqReport, err := operations.ExecuteSequence(s.bundle, offrampops.DeployAndInitCCIPOffRampSequence, s.deps, ccipOffRampSeqInput) + require.NoError(s.T(), err, "failed to execute CCIP OffRamp deploy sequence") + + s.ccipOfframpPackageId = ccipOffRampSeqReport.Output.CCIPOffRampPackageId + s.ccipOfframpObjects = ccipOffRampSeqReport.Output.Objects } func (s *MCMSTestSuite) SignProposal(proposal *mcms.Proposal, roleConfig *RoleConfig) { diff --git a/integration-tests/mcms/mcms_test.go b/integration-tests/mcms/mcms_test.go index aa4c7fd6..d73994b4 100644 --- a/integration-tests/mcms/mcms_test.go +++ b/integration-tests/mcms/mcms_test.go @@ -3,11 +3,8 @@ package mcms import ( - "encoding/hex" "testing" - cselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-deployments-framework/operations" cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" suisdk "github.com/smartcontractkit/mcms/sdk/sui" "github.com/stretchr/testify/require" @@ -18,176 +15,17 @@ import ( module_offramp "github.com/smartcontractkit/chainlink-sui/bindings/generated/ccip/ccip_offramp/offramp" module_onramp "github.com/smartcontractkit/chainlink-sui/bindings/generated/ccip/ccip_onramp/onramp" module_router "github.com/smartcontractkit/chainlink-sui/bindings/generated/ccip/ccip_router" - "github.com/smartcontractkit/chainlink-sui/deployment" ccipops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip" - offrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_offramp" - onrampops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_onramp" - routerops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_router" - linkops "github.com/smartcontractkit/chainlink-sui/deployment/ops/link" mcmsops "github.com/smartcontractkit/chainlink-sui/deployment/ops/mcms" ownershipops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ownership" ) type CCIPMCMSTestSuite struct { MCMSTestSuite - - // CCIP - ccipPackageId string - ccipObjects ccipops.DeployCCIPSeqObjects - linkObjects linkops.DeployLinkObjects - - // Router - ccipRouterPackageId string - ccipRouterObjects routerops.DeployCCIPRouterObjects - - // Onramp - ccipOnrampPackageId string - ccipOnrampObjects onrampops.DeployCCIPOnRampSeqObjects - - // offramp - ccipOfframpPackageId string - ccipOfframpObjects offrampops.DeployCCIPOffRampSeqObjects } func (s *CCIPMCMSTestSuite) SetupSuite() { s.MCMSTestSuite.SetupSuite() - - // Deploy LINK - linkReport, err := cld_ops.ExecuteOperation(s.bundle, linkops.DeployLINKOp, s.deps, cld_ops.EmptyInput{}) - require.NoError(s.T(), err, "failed to deploy LINK token") - - configDigestHex := "e3b1c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - configDigest, err := hex.DecodeString(configDigestHex) - require.NoError(s.T(), err, "failed to decode config digest") - - publicKey1Hex := "8a1b2c3d4e5f60718293a4b5c6d7e8f901234567" - publicKey1, err := hex.DecodeString(publicKey1Hex) - require.NoError(s.T(), err, "failed to decode public key 1") - - publicKey2Hex := "7b8c9dab0c1d2e3f405162738495a6b7c8d9e0f1" - publicKey2, err := hex.DecodeString(publicKey2Hex) - require.NoError(s.T(), err, "failed to decode public key 2") - - publicKey3Hex := "1234567890abcdef1234567890abcdef12345678" - publicKey3, err := hex.DecodeString(publicKey3Hex) - require.NoError(s.T(), err, "failed to decode public key 3") - - publicKey4Hex := "90abcdef1234567890abcdef1234567890abcdef" - publicKey4, err := hex.DecodeString(publicKey4Hex) - require.NoError(s.T(), err, "failed to decode public key 4") - - // Use the same seq as in production deployment - ccipReport, err := cld_ops.ExecuteSequence(s.bundle, ccipops.DeployAndInitCCIPSequence, s.deps, ccipops.DeployAndInitCCIPSeqInput{ - LinkTokenCoinMetadataObjectId: linkReport.Output.Objects.CoinMetadataObjectId, - LocalChainSelector: 1, - DestChainSelector: 2, - DeployCCIPInput: ccipops.DeployCCIPInput{ - McmsPackageId: s.mcmsPackageID, - McmsOwner: s.mcmsOwnerAddress, - }, - MaxFeeJuelsPerMsg: "100000000", - TokenPriceStalenessThreshold: 60, - // Fee Quoter configuration - AddMinFeeUsdCents: []uint32{3000}, - AddMaxFeeUsdCents: []uint32{30000}, - AddDeciBps: []uint16{1000}, - AddDestGasOverhead: []uint32{1000000}, - AddDestBytesOverhead: []uint32{1000}, - AddIsEnabled: []bool{true}, - RemoveTokens: []string{}, - // Fee Quoter destination chain configuration - IsEnabled: true, - MaxNumberOfTokensPerMsg: 2, - MaxDataBytes: 2000, - MaxPerMsgGasLimit: 5000000, - DestGasOverhead: 1000000, - DestGasPerPayloadByteBase: byte(2), - DestGasPerPayloadByteHigh: byte(5), - DestGasPerPayloadByteThreshold: uint16(10), - DestDataAvailabilityOverheadGas: 300000, - DestGasPerDataAvailabilityByte: 4, - DestDataAvailabilityMultiplierBps: 1, - ChainFamilySelector: []byte{0x28, 0x12, 0xd5, 0x2c}, - EnforceOutOfOrder: false, - DefaultTokenFeeUsdCents: 3, - DefaultTokenDestGasOverhead: 100000, - DefaultTxGasLimit: 500000, - GasMultiplierWeiPerEth: 100, - GasPriceStalenessThreshold: 1000000000, - NetworkFeeUsdCents: 10, - // Premium multiplier updates - PremiumMultiplierWeiPerEth: []uint64{10}, - - RmnHomeContractConfigDigest: configDigest, - SignerOnchainPublicKeys: [][]byte{publicKey1, publicKey2, publicKey3, publicKey4}, - NodeIndexes: []uint64{0, 1, 2, 3}, - FSign: uint64(1), - }) - require.NoError(s.T(), err, "failed to execute CCIP deploy sequence") - require.NotEmpty(s.T(), ccipReport.Output.CCIPPackageId, "CCIP package ID should not be empty") - - s.linkObjects = linkReport.Output.Objects - s.ccipPackageId = ccipReport.Output.CCIPPackageId - s.ccipObjects = ccipReport.Output.Objects - - // Deploy Router - routerReport, err := cld_ops.ExecuteOperation(s.bundle, routerops.DeployCCIPRouterOp, s.deps, routerops.DeployCCIPRouterInput{ - McmsPackageId: s.mcmsPackageID, - McmsOwner: s.mcmsOwnerAddress, - }) - require.NoError(s.T(), err, "failed to execute CCIP deploy sequence") - - s.ccipRouterPackageId = routerReport.Output.PackageId - s.ccipRouterObjects = routerReport.Output.Objects - - // Deploy Onramp - ccipOnRampSeqInput := deployment.DefaultOnRampSeqConfig - ccipOnRampSeqInput.DeployCCIPOnRampInput.CCIPPackageId = ccipReport.Output.CCIPPackageId - ccipOnRampSeqInput.DeployCCIPOnRampInput.MCMSPackageId = s.mcmsPackageID - ccipOnRampSeqInput.DeployCCIPOnRampInput.MCMSOwnerPackageId = s.mcmsOwnerAddress - ccipOnRampSeqInput.OnRampInitializeInput.NonceManagerCapId = ccipReport.Output.Objects.NonceManagerCapObjectId - ccipOnRampSeqInput.OnRampInitializeInput.SourceTransferCapId = ccipReport.Output.Objects.SourceTransferCapObjectId - ccipOnRampSeqInput.OnRampInitializeInput.ChainSelector = uint64(s.chainSelector) - ccipOnRampSeqInput.OnRampInitializeInput.FeeAggregator = s.mcmsOwnerAddress - ccipOnRampSeqInput.OnRampInitializeInput.AllowListAdmin = s.mcmsOwnerAddress - ccipOnRampSeqInput.OnRampInitializeInput.DestChainSelectors = []uint64{cselectors.ETHEREUM_MAINNET.Selector} - ccipOnRampSeqInput.OnRampInitializeInput.DestChainRouters = []string{routerReport.Output.PackageId} - ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.DestChainSelector = []uint64{cselectors.ETHEREUM_MAINNET.Selector} - ccipOnRampSeqInput.ApplyAllowListUpdatesInput.DestChainSelector = []uint64{cselectors.ETHEREUM_MAINNET.Selector} - ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.DestChainRouters = []string{routerReport.Output.PackageId} - ccipOnRampSeqInput.ApplyDestChainConfigureOnRampInput.CCIPObjectRefId = ccipReport.Output.Objects.CCIPObjectRefObjectId - - ccipOnRampSeqReport, err := operations.ExecuteSequence(s.bundle, onrampops.DeployAndInitCCIPOnRampSequence, s.deps, ccipOnRampSeqInput) - require.NoError(s.T(), err, "failed to execute CCIP OnRamp deploy sequence") - - s.ccipOnrampPackageId = ccipOnRampSeqReport.Output.CCIPOnRampPackageId - s.ccipOnrampObjects = ccipOnRampSeqReport.Output.Objects - - // Deploy offramp - ccipOffRampSeqInput := deployment.DefaultOffRampSeqConfig - // note: this is a regression, can't acess other chains state very cleanly - onRampBytes := [][]byte{ - {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - } - - // Inject dynamic values for deployment - ccipOffRampSeqInput.CCIPObjectRefId = ccipReport.Output.Objects.CCIPObjectRefObjectId - ccipOffRampSeqInput.DeployCCIPOffRampInput.CCIPPackageId = ccipReport.Output.CCIPPackageId - ccipOffRampSeqInput.DeployCCIPOffRampInput.MCMSPackageId = s.mcmsPackageID - - ccipOffRampSeqInput.InitializeOffRampInput.DestTransferCapId = ccipReport.Output.Objects.DestTransferCapObjectId - ccipOffRampSeqInput.InitializeOffRampInput.FeeQuoterCapId = ccipReport.Output.Objects.FeeQuoterCapObjectId - ccipOffRampSeqInput.InitializeOffRampInput.ChainSelector = uint64(s.chainSelector) - ccipOffRampSeqInput.InitializeOffRampInput.SourceChainSelectors = []uint64{ - cselectors.ETHEREUM_MAINNET.Selector, - } - ccipOffRampSeqInput.InitializeOffRampInput.SourceChainsOnRamp = onRampBytes - - ccipOffRampSeqReport, err := operations.ExecuteSequence(s.bundle, offrampops.DeployAndInitCCIPOffRampSequence, s.deps, ccipOffRampSeqInput) - require.NoError(s.T(), err, "failed to execute CCIP OffRamp deploy sequence") - - s.ccipOfframpPackageId = ccipOffRampSeqReport.Output.CCIPOffRampPackageId - s.ccipOfframpObjects = ccipOffRampSeqReport.Output.Objects } func (s *CCIPMCMSTestSuite) Test_CCIP_MCMS() { diff --git a/integration-tests/mcms/runner_test.go b/integration-tests/mcms/runner_test.go index 28e8914d..2994891d 100644 --- a/integration-tests/mcms/runner_test.go +++ b/integration-tests/mcms/runner_test.go @@ -9,5 +9,13 @@ import ( ) func TestMCMSandCCIPSuite(t *testing.T) { - suite.Run(t, new(CCIPMCMSTestSuite)) + t.Run("CCIPMCMSTestSuite", func(t *testing.T) { + t.Parallel() + suite.Run(t, new(CCIPMCMSTestSuite)) + }) + + t.Run("TokenPoolTestSuite", func(t *testing.T) { + t.Parallel() + suite.Run(t, new(TokenPoolTestSuite)) + }) } diff --git a/integration-tests/mcms/token_pool_test.go b/integration-tests/mcms/token_pool_test.go new file mode 100644 index 00000000..a6edc55f --- /dev/null +++ b/integration-tests/mcms/token_pool_test.go @@ -0,0 +1,603 @@ +//go:build integration + +package mcms + +import ( + "fmt" + "testing" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" + burnminttokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_burn_mint_token_pool" + lockreleasetokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_lock_release_token_pool" + managedtokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_managed_token_pool" + tokenpoolops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ccip_token_pool" + linkops "github.com/smartcontractkit/chainlink-sui/deployment/ops/link" + managedtokenops "github.com/smartcontractkit/chainlink-sui/deployment/ops/managed_token" + mcmsops "github.com/smartcontractkit/chainlink-sui/deployment/ops/mcms" + ownershipops "github.com/smartcontractkit/chainlink-sui/deployment/ops/ownership" + suisdk "github.com/smartcontractkit/mcms/sdk/sui" + "github.com/stretchr/testify/require" +) + +type TokenPoolTestSuite struct { + MCMSTestSuite + + // managed token + managedTokenLinkPackageId string + managedTokenLinkObjects linkops.DeployLinkObjects + managedTokenPackageId string + managedTokenObjects managedtokenops.DeployManagedTokenObjects + + // managed token pool + managedTokenPoolPackageId string + managedTokenPoolObjects managedtokenpoolops.DeployManagedTokenPoolObjects + + // lnr + lnrPackageId string + lnrObjects lockreleasetokenpoolops.DeployLockReleaseTokenPoolObjects + lnrTokenPackageId string + lnrTokenObjects linkops.DeployLinkObjects + + // bnm + bnmPackageId string + bnmObjects burnminttokenpoolops.DeployBurnMintTokenPoolObjects +} + +func (s *TokenPoolTestSuite) SetupSuite() { + s.MCMSTestSuite.SetupSuite() + + // Deploy another link token to wrap into managed token + // Deploy LINK + + // build another reporter, common reporter is getting the report from the prev deployment... + reporter := cld_ops.NewMemoryReporter() + bundle := cld_ops.NewBundle( + s.T().Context, + logger.Test(s.T()), + reporter, + ) + linkManagedTokenReport, err := cld_ops.ExecuteOperation(bundle, linkops.DeployLINKOp, s.deps, cld_ops.EmptyInput{}) + require.NoError(s.T(), err, "failed to deploy LINK token") + s.managedTokenLinkPackageId = linkManagedTokenReport.Output.PackageId + s.managedTokenLinkObjects = linkManagedTokenReport.Output.Objects + + // TODO: Deploy Managed token + managedTokenReport, err := cld_ops.ExecuteSequence(s.bundle, managedtokenops.DeployAndInitManagedTokenSequence, s.deps, managedtokenops.DeployAndInitManagedTokenInput{ + ManagedTokenDeployInput: managedtokenops.ManagedTokenDeployInput{ + MCMSAddress: s.mcmsPackageID, + MCMSOwnerAddress: s.mcmsPackageID, // mcms is the owner + }, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + TreasuryCapObjectId: s.managedTokenLinkObjects.TreasuryCapObjectId, + // configure_new_minter + MinterAddress: s.mcmsOwnerAddress, + Allowance: 1000000, + IsUnlimited: false, + }) + s.Require().NoError(err, "failed to deploy managed token") + s.managedTokenPackageId = managedTokenReport.Output.ManagedTokenPackageId + s.managedTokenObjects = managedTokenReport.Output.Objects + + // Deploy another link token for lnr token pool + reporter = cld_ops.NewMemoryReporter() + bundle = cld_ops.NewBundle( + s.T().Context, + logger.Test(s.T()), + reporter, + ) + + linkReport, err := cld_ops.ExecuteOperation(bundle, linkops.DeployLINKOp, s.deps, cld_ops.EmptyInput{}) + require.NoError(s.T(), err, "failed to deploy LINK token") + s.lnrTokenPackageId = linkReport.Output.PackageId + s.lnrTokenObjects = linkReport.Output.Objects + + linkTokenType := fmt.Sprintf("%s::link::LINK", s.linkPackageId) + secondLinkTokenType := fmt.Sprintf("%s::link::LINK", linkReport.Output.PackageId) + // Deploy a token pool of each class + deployInput := tokenpoolops.DeployAndInitAllTokenPoolsInput{ + SuiChainSelector: uint64(s.chainSelector), + TokenPoolTypes: []string{"bnm", "lnr", "managed"}, + LockReleaseTPInput: lockreleasetokenpoolops.DeployAndInitLockReleaseTokenPoolInput{ + LockReleaseTokenPoolDeployInput: lockreleasetokenpoolops.LockReleaseTokenPoolDeployInput{ + CCIPPackageId: s.ccipPackageId, + MCMSAddress: s.mcmsPackageID, + MCMSOwnerAddress: s.mcmsPackageID, // mcms is the owner + }, + CoinObjectTypeArg: secondLinkTokenType, + CCIPObjectRefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + CoinMetadataObjectId: linkReport.Output.Objects.CoinMetadataObjectId, + TreasuryCapObjectId: linkReport.Output.Objects.TreasuryCapObjectId, + TokenPoolAdministrator: s.mcmsPackageID, + Rebalancer: "0x5555666677778888999900001111222233334444", + // apply chain updates + RemoteChainSelectorsToRemove: []uint64{}, // Empty - no chains to remove from new token pool + RemoteChainSelectorsToAdd: []uint64{4, 5, 6}, + RemotePoolAddressesToAdd: [][]string{{"0x1111111111111111111111111111111111111111"}, {"0x2222222222222222222222222222222222222222"}, {"0x3333333333333333333333333333333333333333"}}, // Must match number of chains + RemoteTokenAddressesToAdd: []string{"0x4444444444444444444444444444444444444444", "0x5555555555555555555555555555555555555555", "0x6666666666666666666666666666666666666666"}, // Must match number of chains + // set chain rate limiter configs + RemoteChainSelectors: []uint64{7, 8, 9}, + OutboundIsEnableds: []bool{true, false, true}, + OutboundCapacities: []uint64{1000000, 2000000, 3000000}, + OutboundRates: []uint64{100, 200, 300}, + InboundIsEnableds: []bool{false, true, false}, + InboundCapacities: []uint64{500000, 1500000, 2500000}, + InboundRates: []uint64{50, 150, 250}, + }, + BurnMintTpInput: burnminttokenpoolops.DeployAndInitBurnMintTokenPoolInput{ + BurnMintTokenPoolDeployInput: burnminttokenpoolops.BurnMintTokenPoolDeployInput{ + CCIPPackageId: s.ccipPackageId, + MCMSAddress: s.mcmsPackageID, + MCMSOwnerAddress: s.mcmsPackageID, // mcms is the owner + }, + CoinObjectTypeArg: linkTokenType, + CCIPObjectRefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + CoinMetadataObjectId: s.linkObjects.CoinMetadataObjectId, + TreasuryCapObjectId: s.linkObjects.TreasuryCapObjectId, + TokenPoolAdministrator: s.mcmsPackageID, + + // apply chain updates + RemoteChainSelectorsToRemove: []uint64{}, // Empty - no chains to remove from new token pool + RemoteChainSelectorsToAdd: []uint64{4, 5, 6}, + RemotePoolAddressesToAdd: [][]string{{"0x1111111111111111111111111111111111111111"}, {"0x2222222222222222222222222222222222222222"}, {"0x3333333333333333333333333333333333333333"}}, // Must match number of chains + RemoteTokenAddressesToAdd: []string{"0x4444444444444444444444444444444444444444", "0x5555555555555555555555555555555555555555", "0x6666666666666666666666666666666666666666"}, // Must match number of chains + // set chain rate limiter configs + RemoteChainSelectors: []uint64{7, 8, 9}, + OutboundIsEnableds: []bool{true, false, true}, + OutboundCapacities: []uint64{1000000, 2000000, 3000000}, + OutboundRates: []uint64{100, 200, 300}, + InboundIsEnableds: []bool{false, true, false}, + InboundCapacities: []uint64{500000, 1500000, 2500000}, + InboundRates: []uint64{50, 150, 250}, + }, + ManagedTPInput: managedtokenpoolops.SeqDeployAndInitManagedTokenPoolInput{ + // deploy + CCIPPackageId: s.ccipPackageId, + ManagedTokenPackageId: s.managedTokenPackageId, + MCMSAddress: s.mcmsPackageID, + MCMSOwnerAddress: s.mcmsPackageID, // mcms is the owner + // initialize + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + CCIPObjectRefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + ManagedTokenStateObjectId: s.managedTokenObjects.StateObjectId, + ManagedTokenOwnerCapId: s.managedTokenObjects.OwnerCapObjectId, + CoinMetadataObjectId: s.managedTokenLinkObjects.CoinMetadataObjectId, + MintCapObjectId: s.managedTokenObjects.MinterCapObjectId, + TokenPoolAdministrator: s.mcmsPackageID, + // apply chain updates + RemoteChainSelectorsToRemove: []uint64{}, // Empty - no chains to remove from new token pool + RemoteChainSelectorsToAdd: []uint64{4, 5, 6}, + RemotePoolAddressesToAdd: [][]string{{"0x1111111111111111111111111111111111111111"}, {"0x2222222222222222222222222222222222222222"}, {"0x3333333333333333333333333333333333333333"}}, // Must match number of chains + RemoteTokenAddressesToAdd: []string{"0x4444444444444444444444444444444444444444", "0x5555555555555555555555555555555555555555", "0x6666666666666666666666666666666666666666"}, // Must match number of chains + // set chain rate limiter configs + RemoteChainSelectors: []uint64{7, 8, 9}, + OutboundIsEnableds: []bool{true, false, true}, + OutboundCapacities: []uint64{1000000, 2000000, 3000000}, + OutboundRates: []uint64{100, 200, 300}, + InboundIsEnableds: []bool{false, true, false}, + InboundCapacities: []uint64{500000, 1500000, 2500000}, + InboundRates: []uint64{50, 150, 250}, + }, + } + + deploymentReport, err := cld_ops.ExecuteSequence(s.bundle, tokenpoolops.DeployAndInitAllTokenPoolsSequence, s.deps, deployInput) + s.Require().NoError(err, "failed to deploy and initialize token pools") + + s.bnmPackageId = deploymentReport.Output.DeployBurnMintTokenPoolOutput.BurnMintTPPackageID + s.bnmObjects = deploymentReport.Output.DeployBurnMintTokenPoolOutput.Objects + + s.lnrPackageId = deploymentReport.Output.DeployLockReleaseTokenPoolOutput.LockReleaseTPPackageID + s.lnrObjects = deploymentReport.Output.DeployLockReleaseTokenPoolOutput.Objects + + s.managedTokenPoolPackageId = deploymentReport.Output.DeployManagedTokenPoolOutput.ManagedTPPackageId + s.managedTokenPoolObjects = deploymentReport.Output.DeployManagedTokenPoolOutput.Objects +} + +func (s *TokenPoolTestSuite) Test_Token_Pool_MCMS() { + s.T().Run("Transfer ownership of token pools to MCMS", func(t *testing.T) { + RunOwnershipTokenPoolProposal(s) + }) + + s.T().Run("Run Lock and Release TP config ops through MCMS", func(t *testing.T) { + RunLnRConfigOpsTokenPoolProposal(s) + }) + + s.T().Run("Run Burn and Mint TP config ops through MCMS", func(t *testing.T) { + RunBnMConfigOpsTokenPoolProposal(s) + }) + + s.T().Run("Run Managed Token TP config ops through MCMS", func(t *testing.T) { + RunManagedConfigOpsTokenPoolProposal(s) + }) +} + +func RunOwnershipTokenPoolProposal(s *TokenPoolTestSuite) { + // 1. Generate proposal to accept the ownership from MCMS + proposalInput := mcmsops.ProposalGenerateInput{ + Defs: []cld_ops.Definition{ + lockreleasetokenpoolops.AcceptOwnershipLockReleaseTokenPoolOp.Def(), + burnminttokenpoolops.AcceptOwnershipBurnMintTokenPoolOp.Def(), + managedtokenpoolops.AcceptOwnershipManagedTokenPoolOp.Def(), + }, + Inputs: []any{ + lockreleasetokenpoolops.AcceptOwnershipLockReleaseTokenPoolInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId)}, + StateObjectId: s.lnrObjects.StateObjectId, + }, + burnminttokenpoolops.AcceptOwnershipBurnMintTokenPoolInput{ + BurnMintTokenPoolPackageId: s.bnmPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.linkPackageId)}, + StateObjectId: s.bnmObjects.StateObjectId, + }, + managedtokenpoolops.AcceptOwnershipManagedTokenPoolInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId)}, + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + }, + }, + + // MCMS related + MmcsPackageID: s.mcmsPackageID, + McmsStateObjID: s.mcmsObj, + TimelockObjID: s.timelockObj, + AccountObjID: s.accountObj, + RegistryObjID: s.registryObj, + + // Proposal + Role: suisdk.TimelockRoleBypasser, + + ChainSelector: uint64(s.chainSelector), + } + + acceptOwnershipProposalReport, err := cld_ops.ExecuteSequence(s.bundle, mcmsops.MCMSDynamicProposalGenerateSeq, s.deps, proposalInput) + s.Require().NoError(err, "executing ownership acceptance proposal sequence") + + timelockProposal := acceptOwnershipProposalReport.Output + + s.ExecuteProposalE2e(&timelockProposal, s.bypasserConfig, 0) + + // 2. Execute transfer ownership from original owner + input := ownershipops.ExecuteOwnershipTransferToMcmsSeqInput{ + BurnMintTokenPool: &burnminttokenpoolops.ExecuteOwnershipTransferToMcmsBurnMintTokenPoolInput{ + BurnMintTokenPoolPackageId: s.bnmPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.linkPackageId)}, + OwnerCapObjectId: s.bnmObjects.OwnerCapObjectId, + StateObjectId: s.bnmObjects.StateObjectId, + RegistryObjectId: s.registryObj, + To: s.mcmsPackageID, + }, + LockReleaseTokenPool: &lockreleasetokenpoolops.ExecuteOwnershipTransferToMcmsLockReleaseTokenPoolInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId)}, + OwnerCapObjectId: s.lnrObjects.OwnerCapObjectId, + StateObjectId: s.lnrObjects.StateObjectId, + RegistryObjectId: s.registryObj, + To: s.mcmsPackageID, + }, + ManagedTokenPool: &managedtokenpoolops.ExecuteOwnershipTransferToMcmsManagedTokenPoolInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + TypeArgs: []string{fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId)}, + OwnerCapObjectId: s.managedTokenPoolObjects.OwnerCapObjectId, + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + RegistryObjectId: s.registryObj, + To: s.mcmsPackageID, + }, + } + + executeOwnershipReport, err := cld_ops.ExecuteSequence(s.bundle, ownershipops.ExecuteOwnershipTransferToMcmsSequence, s.deps, input) + s.Require().NoError(err, "executing ownership transfer to MCMS sequence") // ownership transfer is checked inside the op + + s.Require().NotNil(executeOwnershipReport.Output.Results[ownershipops.ContractTypeBurnMintTokenPool], "burn mint token pool ownership transfer tx is nil") + s.Require().NotNil(executeOwnershipReport.Output.Results[ownershipops.ContractTypeLockReleaseTokenPool], "lock release token pool ownership transfer tx is nil") + s.Require().NotNil(executeOwnershipReport.Output.Results[ownershipops.ContractTypeManagedTokenPool], "managed token pool ownership transfer tx is nil") +} + +func RunLnRConfigOpsTokenPoolProposal(s *TokenPoolTestSuite) { + lnrProposalInput := mcmsops.ProposalGenerateInput{ + Defs: []cld_ops.Definition{ + // lnr config ops + lockreleasetokenpoolops.LockReleaseTokenPoolSetRebalancerOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolSetAllowlistEnabledOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolApplyAllowlistUpdatesOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolApplyChainUpdatesOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolAddRemotePoolOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolRemoveRemotePoolOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolSetChainRateLimiterOp.Def(), + lockreleasetokenpoolops.LockReleaseTokenPoolSetPoolOp.Def(), // Disabled as TAR caller issue + }, + Inputs: []any{ + // lnr config ops + lockreleasetokenpoolops.LockReleaseTokenPoolSetRebalancerInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + Rebalancer: "0x9999000011112222333344445555666677778888", + }, + lockreleasetokenpoolops.LockReleaseTokenPoolSetAllowlistEnabledInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + Enabled: true, + }, + lockreleasetokenpoolops.LockReleaseTokenPoolApplyAllowlistUpdatesInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + Removes: []string{}, + Adds: []string{"0x1111111111111111111111111111111111111111"}, + }, + lockreleasetokenpoolops.LockReleaseTokenPoolApplyChainUpdatesInput{ + LockReleasePackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + RemoteChainSelectorsToRemove: []uint64{}, + RemoteChainSelectorsToAdd: []uint64{421}, // Use a different chain selector to avoid conflicts with initial setup + RemotePoolAddressesToAdd: [][]string{{"0x2222222222222222222222222222222222222222"}}, + RemoteTokenAddressesToAdd: []string{"0x3333333333333333333333333333333333333333"}, + }, + lockreleasetokenpoolops.LockReleaseTokenPoolAddRemotePoolInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + RemoteChainSelector: 421, // Use the same chain we added in ApplyChainUpdates + RemotePoolAddress: "0x4444444444444444444444444444444444444444", + }, + lockreleasetokenpoolops.LockReleaseTokenPoolRemoveRemotePoolInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + RemoteChainSelector: 421, // Remove from the same chain we just added to + RemotePoolAddress: "0x4444444444444444444444444444444444444444", // Remove the same pool we just added + }, + lockreleasetokenpoolops.LockReleaseTokenPoolSetChainRateLimiterInput{ + LockReleasePackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + RemoteChainSelectors: []uint64{420}, + OutboundIsEnableds: []bool{true}, + OutboundCapacities: []uint64{1000000}, + OutboundRates: []uint64{100000}, + InboundIsEnableds: []bool{true}, + InboundCapacities: []uint64{2000000}, + InboundRates: []uint64{200000}, + }, + lockreleasetokenpoolops.LockReleaseTokenPoolSetPoolInput{ + LockReleaseTokenPoolPackageId: s.lnrPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.lnrTokenPackageId), + RefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + StateObjectId: s.lnrObjects.StateObjectId, + OwnerCap: s.lnrObjects.OwnerCapObjectId, + CoinMetadataAddress: s.lnrTokenObjects.CoinMetadataObjectId, + }, + }, + + // MCMS related + MmcsPackageID: s.mcmsPackageID, + McmsStateObjID: s.mcmsObj, + TimelockObjID: s.timelockObj, + AccountObjID: s.accountObj, + RegistryObjID: s.registryObj, + + // Proposal + Role: suisdk.TimelockRoleBypasser, + + ChainSelector: uint64(s.chainSelector), + } + + // Execute LNR proposal + proposalReport, err := cld_ops.ExecuteSequence(s.bundle, mcmsops.MCMSDynamicProposalGenerateSeq, s.deps, lnrProposalInput) + s.Require().NoError(err, "executing ownership acceptance proposal sequence") + + timelockProposal := proposalReport.Output + + s.ExecuteProposalE2e(&timelockProposal, s.bypasserConfig, 0) +} + +func RunBnMConfigOpsTokenPoolProposal(s *TokenPoolTestSuite) { + bnmProposalInput := mcmsops.ProposalGenerateInput{ + Defs: []cld_ops.Definition{ + // bnm config ops + burnminttokenpoolops.BurnMintTokenPoolSetAllowlistEnabledOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolApplyAllowlistUpdatesOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolApplyChainUpdatesOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolAddRemotePoolOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolRemoveRemotePoolOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolSetChainRateLimiterOp.Def(), + burnminttokenpoolops.BurnMintTokenPoolSetPoolOp.Def(), // Disabled as TAR caller issue + }, + Inputs: []any{ + // bnm config ops + burnminttokenpoolops.BurnMintTokenPoolSetAllowlistEnabledInput{ + BurnMintPackageId: s.bnmPackageId, + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + Enabled: true, + }, + burnminttokenpoolops.BurnMintTokenPoolApplyAllowlistUpdatesInput{ + BurnMintPackageId: s.bnmPackageId, + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + Removes: []string{}, + Adds: []string{"0x1111111111111111111111111111111111111111"}, + }, + burnminttokenpoolops.BurnMintTokenPoolApplyChainUpdatesInput{ + BurnMintPackageId: s.bnmPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + RemoteChainSelectorsToRemove: []uint64{}, + RemoteChainSelectorsToAdd: []uint64{419}, + RemotePoolAddressesToAdd: [][]string{{"0x8888888888888888888888888888888888888888"}}, // Use different pool address to avoid conflict + RemoteTokenAddressesToAdd: []string{"0x9999999999999999999999999999999999999999"}, // Use different token address too + }, + burnminttokenpoolops.BurnMintTokenPoolAddRemotePoolInput{ + BurnMintTokenPoolPackageId: s.bnmPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + RemoteChainSelector: 5, // Add to existing chain 5 that already has pools + RemotePoolAddress: "0x7777777777777777777777777777777777777777", // New pool address + }, + burnminttokenpoolops.BurnMintTokenPoolRemoveRemotePoolInput{ + BurnMintPackageId: s.bnmPackageId, + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + RemoteChainSelector: 5, // Remove from existing chain 5 + RemotePoolAddress: "0x2222222222222222222222222222222222222222", // Remove the pool that exists from initial setup + }, + burnminttokenpoolops.BurnMintTokenPoolSetChainRateLimiterInput{ + BurnMintPackageId: s.bnmPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + RemoteChainSelectors: []uint64{419}, // Use the chain we added in ApplyChainUpdates + OutboundIsEnableds: []bool{true}, + OutboundCapacities: []uint64{1000000}, + OutboundRates: []uint64{100000}, + InboundIsEnableds: []bool{true}, + InboundCapacities: []uint64{2000000}, + InboundRates: []uint64{200000}, + }, + burnminttokenpoolops.BurnMintTokenPoolSetPoolInput{ + BurnMintTokenPoolPackageId: s.bnmPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.linkPackageId), + RefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + StateObjectId: s.bnmObjects.StateObjectId, + OwnerCap: s.bnmObjects.OwnerCapObjectId, + CoinMetadataAddress: s.lnrTokenObjects.CoinMetadataObjectId, + }, + }, + + // MCMS related + MmcsPackageID: s.mcmsPackageID, + McmsStateObjID: s.mcmsObj, + TimelockObjID: s.timelockObj, + AccountObjID: s.accountObj, + RegistryObjID: s.registryObj, + + // Proposal + Role: suisdk.TimelockRoleBypasser, + + ChainSelector: uint64(s.chainSelector), + } + + // Execute BNM proposal + proposalReport, err := cld_ops.ExecuteSequence(s.bundle, mcmsops.MCMSDynamicProposalGenerateSeq, s.deps, bnmProposalInput) + s.Require().NoError(err, "executing ownership acceptance proposal sequence") + + timelockProposal := proposalReport.Output + + s.ExecuteProposalE2e(&timelockProposal, s.bypasserConfig, 0) + +} + +func RunManagedConfigOpsTokenPoolProposal(s *TokenPoolTestSuite) { + managedProposalInput := mcmsops.ProposalGenerateInput{ + Defs: []cld_ops.Definition{ + // managed config ops + managedtokenpoolops.ManagedTokenPoolSetAllowlistEnabledOp.Def(), + managedtokenpoolops.ManagedTokenPoolApplyAllowlistUpdatesOp.Def(), + managedtokenpoolops.ManagedTokenPoolApplyChainUpdatesOp.Def(), + managedtokenpoolops.ManagedTokenPoolAddRemotePoolOp.Def(), + managedtokenpoolops.ManagedTokenPoolRemoveRemotePoolOp.Def(), + managedtokenpoolops.ManagedTokenPoolSetChainRateLimiterOp.Def(), + managedtokenpoolops.ManagedTokenPoolSetPoolOp.Def(), // Disabled as TAR caller issue + }, + Inputs: []any{ + managedtokenpoolops.ManagedTokenPoolSetAllowlistEnabledInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + Enabled: true, + }, + managedtokenpoolops.ManagedTokenPoolApplyAllowlistUpdatesInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + Removes: []string{}, + Adds: []string{"0x1111111111111111111111111111111111111111"}, + }, + managedtokenpoolops.ManagedTokenPoolApplyChainUpdatesInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + RemoteChainSelectorsToRemove: []uint64{}, + RemoteChainSelectorsToAdd: []uint64{421}, + RemotePoolAddressesToAdd: [][]string{{"0x8888888888888888888888888888888888888888"}}, // Use different pool address to avoid conflict + RemoteTokenAddressesToAdd: []string{"0x9999999999999999999999999999999999999999"}, // Use different token address too + }, + managedtokenpoolops.ManagedTokenPoolAddRemotePoolInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + RemoteChainSelector: 421, // Use the same chain we added in ApplyChainUpdates + RemotePoolAddress: "0x4444444444444444444444444444444444444444", + }, + managedtokenpoolops.ManagedTokenPoolRemoveRemotePoolInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + RemoteChainSelector: 421, // Remove from the same chain we just added to + RemotePoolAddress: "0x4444444444444444444444444444444444444444", // Remove the same pool we just added + }, + managedtokenpoolops.ManagedTokenPoolSetChainRateLimiterInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + RemoteChainSelectors: []uint64{419}, // Use the same chain we added in ApplyChainUpdates + OutboundIsEnableds: []bool{true}, + OutboundCapacities: []uint64{1000000}, + OutboundRates: []uint64{100000}, + InboundIsEnableds: []bool{true}, + InboundCapacities: []uint64{2000000}, + InboundRates: []uint64{200000}, + }, + managedtokenpoolops.ManagedTokenPoolSetPoolInput{ + ManagedTokenPoolPackageId: s.managedTokenPoolPackageId, + CoinObjectTypeArg: fmt.Sprintf("%s::link::LINK", s.managedTokenLinkPackageId), + RefObjectId: s.ccipObjects.CCIPObjectRefObjectId, + StateObjectId: s.managedTokenPoolObjects.StateObjectId, + OwnerCap: s.managedTokenPoolObjects.OwnerCapObjectId, + CoinMetadataAddress: s.managedTokenLinkObjects.CoinMetadataObjectId, + ManagedTokenState: s.managedTokenObjects.StateObjectId, + }, + }, + + // MCMS related + MmcsPackageID: s.mcmsPackageID, + McmsStateObjID: s.mcmsObj, + TimelockObjID: s.timelockObj, + AccountObjID: s.accountObj, + RegistryObjID: s.registryObj, + + // Proposal + Role: suisdk.TimelockRoleBypasser, + + ChainSelector: uint64(s.chainSelector), + } + + // Execute Managed proposal + proposalReport, err := cld_ops.ExecuteSequence(s.bundle, mcmsops.MCMSDynamicProposalGenerateSeq, s.deps, managedProposalInput) + s.Require().NoError(err, "executing ownership acceptance proposal sequence") + + timelockProposal := proposalReport.Output + + s.ExecuteProposalE2e(&timelockProposal, s.bypasserConfig, 0) +}