diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 369c620e3..63678eab5 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -30,6 +30,7 @@ import ( ethclient "github.com/ethereum/go-ethereum/ethclient" ethrpc "github.com/ethereum/go-ethereum/rpc" + smcerror "github.com/0xPolygon/polygon-cli/errors" "github.com/0xPolygon/polygon-cli/bindings/tokens" "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/0xPolygon/polygon-cli/bindings/ulxly/polygonrollupmanager" @@ -545,12 +546,12 @@ type JsonError struct { Data interface{} `json:"data"` } -func logAndReturnJsonError(cmd *cobra.Command, client *ethclient.Client, tx *types.Transaction, opts *bind.TransactOpts, err error) error { +func logAndReturnJsonError(ctx context.Context, client *ethclient.Client, tx *types.Transaction, opts *bind.TransactOpts, err error) error { var callErr error if tx != nil { // in case the error came down to gas estimation, we can sometimes get more information by doing a call - _, callErr = client.CallContract(cmd.Context(), ethereum.CallMsg{ + _, callErr = client.CallContract(ctx, ethereum.CallMsg{ From: opts.From, To: tx.To(), Gas: tx.Gas(), @@ -599,24 +600,30 @@ func logAndReturnJsonError(cmd *cobra.Command, client *ethclient.Client, tx *typ return err } + reason, decodeErr := smcerror.DecodeSmcErrorCode(jsonError.Data) + if decodeErr != nil { + log.Error().Err(err).Msg("unable to decode smart contract error") + return err + } errLog := log.Error(). Err(err). Str("message", jsonError.Message). Int("code", jsonError.Code). - Interface("data", jsonError.Data) + Interface("data", jsonError.Data). + Str("reason", reason) if callErr != nil { errLog = errLog.Err(callErr) } + customErr := errors.New(err.Error()+": " + reason) if errCode, isValid := jsonError.Data.(string); isValid && errCode == "0x646cf558" { // I don't want to bother with the additional error logging for previously claimed deposits - return err + return customErr } errLog.Msg("Unable to interact with bridge contract") - - return err + return customErr } // Function to parse deposit count from bridge transaction logs @@ -725,7 +732,7 @@ func bridgeAsset(cmd *cobra.Command) error { // Approve the bridge contract to spend the tokens on behalf of the user approveTxn, iErr := tokenContract.Approve(auth, bridgeAddress, value) - if iErr = logAndReturnJsonError(cmd, client, approveTxn, auth, iErr); iErr != nil { + if iErr = logAndReturnJsonError(cmd.Context(), client, approveTxn, auth, iErr); iErr != nil { return iErr } log.Info().Msg("approveTxn: " + approveTxn.Hash().String()) @@ -736,7 +743,7 @@ func bridgeAsset(cmd *cobra.Command) error { } bridgeTxn, err := bridgeV2.BridgeAsset(auth, destinationNetwork, toAddress, value, tokenAddress, isForced, callData) - if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, bridgeTxn, auth, err); err != nil { log.Info().Err(err).Str("calldata", callDataString).Msg("Bridge transaction failed") return err } @@ -790,7 +797,7 @@ func bridgeMessage(cmd *cobra.Command) error { } bridgeTxn, err := bridgeV2.BridgeMessage(auth, destinationNetwork, toAddress, isForced, callData) - if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, bridgeTxn, auth, err); err != nil { log.Info().Err(err).Str("calldata", callDataString).Msg("Bridge transaction failed") return err } @@ -847,7 +854,7 @@ func bridgeWETHMessage(cmd *cobra.Command) error { callData := common.Hex2Bytes(strings.TrimPrefix(callDataString, "0x")) bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) - if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, bridgeTxn, auth, err); err != nil { log.Info().Err(err).Str("calldata", callDataString).Msg("Bridge transaction failed") return err } @@ -911,7 +918,7 @@ func claimAsset(cmd *cobra.Command) error { merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) - if err = logAndReturnJsonError(cmd, client, claimTxn, auth, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, claimTxn, auth, err); err != nil { return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) @@ -964,7 +971,7 @@ func claimMessage(cmd *cobra.Command) error { merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) - if err = logAndReturnJsonError(cmd, client, claimTxn, auth, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, claimTxn, auth, err); err != nil { return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) @@ -1252,7 +1259,7 @@ func claimSingleDeposit(cmd *cobra.Command, client *ethclient.Client, bridgeCont claimTx, err = bridgeContract.ClaimMessage(opts, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), deposit.OrigNet, originAddress, deposit.DestNet, toAddress, amount, metadata) } - if err = logAndReturnJsonError(cmd, client, claimTx, opts, err); err != nil { + if err = logAndReturnJsonError(cmd.Context(), client, claimTx, opts, err); err != nil { log.Warn(). Uint32("DepositCnt", deposit.DepositCnt). Uint32("OrigNet", deposit.OrigNet). diff --git a/errors/smc.go b/errors/smc.go new file mode 100644 index 000000000..9dd296ae2 --- /dev/null +++ b/errors/smc.go @@ -0,0 +1,245 @@ +package errors + +import "errors" + +var ErrorMessages = map[string]string{ + "0x812a372d":"BatchAlreadyVerifiedError", + "0x98c5c014":"BatchNotSequencedOrNotSequenceEndError", + "0xb59f753a":"ExceedMaxVerifyBatchesError", + "0xb9b18f57":"FinalNumBatchBelowLastVerifiedBatchError", + "0x32a2a77f":"FinalNumBatchDoesNotMatchPendingStateError", + "0xbfa7079f":"FinalPendingStateNumInvalidError", + "0x24eff8c3":"ForceBatchNotAllowedError", + "0xc44a0821":"ForceBatchTimeoutNotExpiredError", + "0xf6ba91a1":"ForceBatchesAlreadyActiveError", + "0xc630a00d":"ForceBatchesOverflowError", + "0xce3d755e":"ForcedDataDoesNotMatchError", + "0x73bd668d":"GlobalExitRootNotExistError", + "0xd257555a":"HaltTimeoutNotExpiredError", + "0x1e56e9e2":"InitNumBatchAboveLastVerifiedBatchError", + "0x2bd2e3e7":"InitNumBatchDoesNotMatchPendingStateError", + "0x09bde339":"InvalidProofError", + "0xe067dfe8":"InvalidRangeBatchTimeTargetError", + "0xf5e37f2f":"InvalidRangeForceBatchTimeoutError", + "0x4c2533c8":"InvalidRangeMultiplierBatchFeeError", + "0x66385b51":"NewAccInputHashDoesNotExistError", + "0x48a05a90":"NewPendingStateTimeoutMustBeLowerError", + "0x176b913c":"NewStateRootNotInsidePrimeError", + "0x401636df":"NewTrustedAggregatorTimeoutMustBeLowerError", + "0x4732fdb5":"NotEnoughMaticAmountError", + "0x6818c29e":"OldAccInputHashDoesNotExistError", + "0x4997b986":"OldStateRootDoesNotExistError", + "0x47556579": "OnlyAdminError", + "0x53866981":"OnlyEmergencyStateError", + "0x2f0047fc":"OnlyNotEmergencyStateError", + "0xd1ec4b23":"OnlyPendingAdminError", + "0xbbcbbc05":"OnlyTrustedAggregatorError", + "0x11e7be15":"OnlyTrustedSequencerError", + "0xbb14c205":"PendingStateDoesNotExistError", + "0xd086b70b":"PendingStateInvalidError", + "0x0ce9e4a2":"PendingStateNotConsolidableError", + "0xcc965070":"PendingStateTimeoutExceedHaltAggregationTimeoutError", + "0xcb591a5f":"SequenceZeroBatchesError", + "0x7f7ab872":"SequencedTimestampBelowForcedTimestampError", + "0xea827916":"SequencedTimestampInvalidError", + "0xa47276bd":"StoredRootMustBeDifferentThanNewRootError", + "0xa29a6c7c":"TransactionsLengthAboveMaxError", + "0x1d06e879":"TrustedAggregatorTimeoutExceedHaltAggregationTimeoutError", + "0x8a0704d3":"TrustedAggregatorTimeoutNotExpiredError", + "0x646cf558":"AlreadyClaimedError", + "0xb89240f5":"AmountDoesNotMatchMsgValueError", + "0x0595ea2e":"DestinationNetworkInvalidError", + "0x6747a288":"EtherTransferFailedError", + "0x002f6fad":"GlobalExitRootInvalidError", + "0xe0417cec":"InvalidSmtProofError", + "0xef5ccf66":"MerkleTreeFullError", + "0x37e391c3":"MessageFailedError", + "0x798ee6f1":"MsgValueNotZeroError", + "0x03fffc4b":"NotValidAmountError", + "0x912ecce7":"NotValidOwnerError", + "0xe282c0ba":"NotValidSignatureError", + "0x750643af":"NotValidSpenderError", + "0xe2e8106b":"OnlyPolygonZkEVMError", + "0x1f97a582":"GlobalExitRootAlreadySetError", + "0xf4a66f9d":"GlobalExitRootNotFoundError", + "0xf6b2911f":"InvalidZeroAddressError", + "0xb49365dd":"OnlyAllowedContractsError", + "0xa34ddeb1":"OnlyGlobalExitRootRemoverError", + "0xc758fc1a":"OnlyGlobalExitRootUpdaterError", + "0x7ca4d27a":"OnlyPendingGlobalExitRootRemoverError", + "0x5f063f01":"OnlyPendingGlobalExitRootUpdaterError", + "0xc10b1590":"VersionAlreadyUpdatedError", + "0x9996b315":"AddressEmptyCodeError", + "0xcd786059":"AddressInsufficientBalanceError", + "0x1ae0e033":"BridgeAddressNotAllowedError", + "0x1425ea42":"FailedInnerCallError", + "0x62d05d1a":"FailedProxyDeploymentError", + "0x1a874c12":"GasTokenNetworkMustBeZeroOnEtherError", + "0xf57ac683":"InvalidInitializeFunctionError", + "0x188f622f":"InvalidProxyAdminError", + "0x54a0d80a":"InvalidZeroProxyAdminOwnerError", + "0xdde3cda7":"NativeTokenIsEtherError", + "0x6f625c40":"NoValueInMessagesOnGasTokenNetworksError", + "0x2d67bc9c":"OnlyPendingProxiedTokensManagerError", + "0x08667503":"OnlyProxiedTokensManagerError", + "0xb9b3a2c8":"OnlyRollupManagerError", + "0x5274afe7":"SafeERC20FailedOperationError", + "0xf645eedf":"ECDSAInvalidSignatureError", + "0xfce698f7":"ECDSAInvalidSignatureLengthError", + "0xd78bce0c":"ECDSAInvalidSignatureSError", + "0xfb8f41b2":"ERC20InsufficientAllowanceError", + "0xe450d38c":"ERC20InsufficientBalanceError", + "0xe602df05":"ERC20InvalidApproverError", + "0xec442f05":"ERC20InvalidReceiverError", + "0x96c6fd1e":"ERC20InvalidSenderError", + "0x94280d62":"ERC20InvalidSpenderError", + "0x62791302":"ERC2612ExpiredSignatureError", + "0x4b800e46":"ERC2612InvalidSignerError", + "0x752d88c0":"InvalidAccountNonceError", + "0xf92ee8a9":"InvalidInitializationError", + "0xd7e6bcf8":"NotInitializingError", + "0x38da3b15":"OnlyBridgeError", + "0x988066a1":"WrongVerifierSelectorError", + "0xead1340b":"InitBatchMustMatchCurrentForkIDError", + "0x6697b232":"AccessControlBadConfirmationError", + "0xe2517d3f":"AccessControlUnauthorizedAccountError", + "0x22a1bdc4":"AggchainVKeyAlreadyExistsError", + "0x925e5a3a":"AggchainVKeyNotFoundError", + "0xae80851c":"InvalidProofBytesLengthError", + "0x4c939ed7":"OnlyAggLayerAdminError", + "0xce074d87":"OnlyPendingAggLayerAdminError", + "0x7500f209":"PPSelectorCannotBeZeroError", + "0x4bc7c278":"RouteAlreadyExistsError", + "0xc7b4a1f2":"RouteIsAlreadyFrozenError", + "0xebf10823":"RouteIsFrozenError", + "0xf208777e":"RouteNotFoundError", + "0x6745305e":"VKeyCannotBeZeroError", + "0x5a568e68":"AccessControlOnlyCanRenounceRolesForSelfError", + "0xec2b7c3e":"AddressDoNotHaveRequiredRoleError", + "0x0ded782d":"AggchainDataMustBeZeroForPessimisticVerifierTypeError", + "0x44541072":"AllBatchesMustBeVerifiedError", + "0xcc862d4a":"AllSequencedMustBeVerifiedError", + "0x5c998a86":"AllzkEVMSequencedBatchesMustBeVerifiedError", + "0x85869525":"BatchFeeOutOfRangeError", + "0x9d59507b":"CannotUpdateWithUnconsolidatedPendingStateError", + "0x6f91fc12":"ChainIDAlreadyExistError", + "0x4c753f57":"ChainIDOutOfRangeError", + "0x8a51facb":"EmptyVerifySequencesDataError", + "0x42f31f92":"FinalNumSequenceBelowLastVerifiedSequenceError", + "0xb7d5b4a3":"FinalNumSequenceDoesNotMatchPendingStateError", + "0xf5f2eb13":"InitSequenceMustMatchCurrentForkIDError", + "0x686446b1":"InitSequenceNumDoesNotMatchPendingStateError", + "0x85db4c96":"InvalidConstructorInputsError", + "0xc970156c":"InvalidImplementationAddressError", + "0x6fc5557f":"InvalidInputsForRollupTypeError", + "0x52ad525a":"InvalidPessimisticProofError", + "0x44ceee73":"InvalidRangeMultiplierZkGasPriceError", + "0xe04b5d74":"InvalidRangeSequenceTimeTargetError", + "0x43ba19f2":"InvalidRollupError", + "0x63d722e7":"InvalidRollupTypeError", + "0x10c40e8c":"InvalidVerifierAddressError", + "0xe4ffd914":"InvalidVerifierTypeError", + "0xa60721e1":"L1InfoTreeLeafCountInvalidError", + "0x2590ccf9":"MustSequenceSomeBatchError", + "0x562a9374":"MustSequenceSomeBlobError", + "0x1a06d0fe":"NotAllowedAddressError", + "0x696072e9":"OnlyRollupAdminError", + "0x90db0d07":"OnlyStateTransitionChainsError", + "0x60dbf8ae":"PendingStateNumExistError", + "0x3ee5aeb5":"ReentrancyGuardReentrantCallError", + "0x9753965f":"RollbackBatchIsNotEndOfSequenceError", + "0xcb23ebdf":"RollbackBatchIsNotValidError", + "0xd409b930":"RollupAddressAlreadyExistError", + "0x51fcf62a":"RollupIDNotAscendingOrderError", + "0x74a086a3":"RollupMustExistError", + "0x7512e5cb":"RollupTypeDoesNotExistError", + "0x3b8d3d99":"RollupTypeObsoleteError", + "0x71653c15":"SenderMustBeRollupError", + "0x5b6602b7":"StateTransitionChainsNotAllowedError", + "0xb541abe2":"UpdateNotCompatibleError", + "0x3e37e233":"UpdateToOldRollupTypeIDError", + "0x4f61d519":"UpdateToSameRollupTypeIDError", + "0x0c0bbd27":"zkGasPriceOfRangeError", + "0xd6bdac3f":"AggchainManagerCannotBeZeroError", + "0xda5bceb9":"FinalAccInputHashDoesNotMatchError", + "0xc89374d8":"ForceBatchesDecentralizedError", + "0x39258d18":"ForceBatchesNotAllowedOnEmergencyStateError", + "0x3d49ed4c":"HaltTimeoutNotExpiredAfterEmergencyStateError", + "0x248b8f82":"HugeTokenMetadataNotSupportedError", + "0x1a070d9a":"InitSequencedBatchDoesNotMatchError", + "0xae7e6e0f":"InvalidAggLayerGatewayAddressError", + "0x30639654":"InvalidAggchainDataLengthError", + "0x45707950":"InvalidAggchainTypeError", + "0xcd161966":"InvalidInitializeTransactionError", + "0xadc06ae7":"InvalidInitializerError", + "0x0a00feb3":"MaxTimestampSequenceInvalidError", + "0x2354600f":"NotEnoughPOLAmountError", + "0x660a7ce5":"OnlyAggchainManagerError", + "0x3ac87ac9":"OnlyPendingAggchainManagerError", + "0x05882cf0":"OnlyPendingVKeyManagerError", + "0xe4d753bd":"OnlyVKeyManagerError", + "0xe3cc7610":"OwnedAggchainVKeyAlreadyAddedError", + "0xf360deaf":"OwnedAggchainVKeyNotFoundError", + "0x62de0445":"UseDefaultGatewayAlreadyDisabledError", + "0x93be8051":"UseDefaultGatewayAlreadyEnabledError", + "0xe1dbcf2e":"ZeroValueAggchainVKeyError", + "0x580a5fa8":"AggregationVkeyMustBeDifferentThanZeroError", + "0x0dffe818":"CannotProposeFutureL2OutputError", + "0x541d595b":"L2BlockNumberLessThanNextBlockNumberError", + "0xff5f8600":"L2BlockTimeMustBeGreaterThanZeroError", + "0x80bcf515":"L2OutputRootCannotBeZeroError", + "0x43826089":"OnlyOptimisticModeManagerError", + "0x93f1e094":"OnlyPendingOptimisticModeManagerError", + "0x98b31779":"OptimisticModeEnabledError", + "0x873dabd2":"OptimisticModeNotEnabledError", + "0x87b761a2":"RangeVkeyCommitmentMustBeDifferentThanZeroError", + "0x4bf41e17":"RollupConfigHashMustBeDifferentThanZeroError", + "0x2403afcb":"StartL2TimestampMustBeLessThanCurrentTimeError", + "0xd685d8e7":"SubmissionIntervalMustBeGreaterThanZeroError", + "0xe12afaf5":"CommitteeAddressDoesNotExistError", + "0xb54b70e4":"EmptyURLNotAllowedError", + "0x2e7dcd6e":"TooManyRequiredSignaturesError", + "0x6b8eec46":"UnexpectedAddrsAndSignaturesSizeError", + "0x2ab6a129":"UnexpectedAddrsBytesLengthError", + "0x6b156b28":"UnexpectedCommitteeHashError", + "0xd53cfbe0":"WrongAddrOrderError", + "0x821935b4":"SequenceWithDataAvailabilityNotAllowedError", + "0x5f0e7abe":"SwitchToSameValueError", + "0x318dafb8":"ClaimNotSetError", + "0x441845b1":"EmergencyStateNotAllowedError", + "0x869e93ea":"InputArraysLengthMismatchError", + "0x1cdc46ea":"InvalidSovereignWETHAddressParamsError", + "0x4e702fa5":"InvalidZeroNetworkIDError", + "0x23d72133":"LocalBalanceTreeOverflowError", + "0x14603c01":"LocalBalanceTreeUnderflowError", + "0xaf6e71a2":"OnlyBridgeManagerError", + "0x26898bbe":"OnlyEmergencyBridgePauserError", + "0x8e9d821f":"OnlyEmergencyBridgeUnpauserError", + "0x7bb0100f":"OnlyPendingEmergencyBridgePauserError", + "0xd491f0c1":"OnlyPendingEmergencyBridgeUnpauserError", + "0x658b23ad":"OriginNetworkInvalidError", + "0x5eaf7bac":"TokenAlreadyMappedError", + "0xe273c4a1":"TokenAlreadyUpdatedError", + "0x828d5663":"TokenNotMappedError", + "0xe0c897a7":"TokenNotRemappedError", + "0x9968e226":"WETHRemappingNotSupportedOnGasTokenNetworksError", + "0x5c3f3c1e":"InvalidZeroProxyAdminOwnerError", + "0x62e77ba2":"ERC1967InvalidAdminError", + "0x4c9c8ce3":"ERC1967InvalidImplementationError", + "0xb398979f":"ERC1967NonPayableError", + "0xbefb0920":"FailedTokenWrappedDeploymentError", + "0x56feb4f5":"NotEnoughGlobalExitRootsInsertedError", + "0xae765ff6":"NotLastInsertedGlobalExitRootError", + "0x3a64d973":"OnlyChainsWithPessimisticProofsError", +} + +func DecodeSmcErrorCode(errorCode interface{}) (string, error) { + codeStr, ok := errorCode.(string) + if !ok { + return "", errors.New("jsonError.Data is not a string, unable to decode smart contract error") + } + if msg, exists := ErrorMessages[codeStr]; exists { + return msg, nil + } + return codeStr + " (unknown selector)", nil +} diff --git a/errors/smc_test.go b/errors/smc_test.go new file mode 100644 index 000000000..d49cd2d48 --- /dev/null +++ b/errors/smc_test.go @@ -0,0 +1,33 @@ +package errors_test + +import ( + "testing" + + "github.com/0xPolygon/polygon-cli/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDecodeSmcErrorCode (t *testing.T) { + reason, err := errors.DecodeSmcErrorCode("0x1a070d9a") + require.NoError(t, err) + assert.Equal(t, "InitSequencedBatchDoesNotMatchError", reason) + + reason, err = errors.DecodeSmcErrorCode("0x52ad525a") + require.NoError(t, err) + assert.Equal(t, "InvalidPessimisticProofError", reason) + + reason, err = errors.DecodeSmcErrorCode("0x9aad315a") + require.NoError(t, err) + assert.Equal(t, "0x9aad315a (unknown selector)", reason) + + var emptyInterface interface{} + _, err = errors.DecodeSmcErrorCode(emptyInterface) + require.Error(t, err) + + code := "0x3bbd317c" + reason, err = errors.DecodeSmcErrorCode(code) + require.NoError(t, err) + assert.Equal(t, "0x3bbd317c (unknown selector)", reason) +} +