package pump_parser import ( "encoding/binary" "errors" ) type TransactionErrorVariant uint32 type InstructionErrorVariant uint32 type InstructionErrorEnum struct { Index uint8 Variant InstructionErrorVariant rest []byte } type CustomInstructionErrorEnum struct { Code uint32 } const ( AccountInUse TransactionErrorVariant = iota AccountLoadedTwice AccountNotFound ProgramAccountNotFound InsufficientFundsForFee InvalidAccountForFee AlreadyProcessed BlockhashNotFound InstructionError //InstructionError(u8, InstructionError), CallChainTooDeep MissingSignatureForFee InvalidAccountIndex SignatureFailure InvalidProgramForExecution SanitizeFailure ClusterMaintenance AccountBorrowOutstanding WouldExceedMaxBlockCostLimit UnsupportedVersion InvalidWritableAccount WouldExceedMaxAccountCostLimit WouldExceedAccountDataBlockLimit TooManyAccountLocks AddressLookupTableNotFound InvalidAddressLookupTableOwner InvalidAddressLookupTableData InvalidAddressLookupTableIndex InvalidRentPayingAccount WouldExceedMaxVoteCostLimit WouldExceedAccountDataTotalLimit DuplicateInstruction //DuplicateInstruction(u8), /* InsufficientFundsForRent { account_index: u8, }, */ InsufficientFundsForRent MaxLoadedAccountsDataSizeExceeded InvalidLoadedAccountsDataSizeLimit ResanitizationNeeded /* ProgramExecutionTemporarilyRestricted { account_index: u8, }, */ ProgramExecutionTemporarilyRestricted UnbalancedTransaction ProgramCacheHitMaxLimit CommitCancelled ) const ( GenericError InstructionErrorVariant = iota /// The arguments provided to a program were invalid InvalidArgument /// An instruction's data contents were invalid InvalidInstructionData /// An account's data contents was invalid InvalidAccountData /// An account's data was too small AccountDataTooSmall /// An account's balance was too small to complete the instruction InsufficientFunds /// The account did not have the expected program id IncorrectProgramId /// A signature was required but not found MissingRequiredSignature /// An initialize instruction was sent to an account that has already been initialized. AccountAlreadyInitialized /// An attempt to operate on an account that hasn't been initialized. UninitializedAccount /// Program's instruction lamport balance does not equal the balance after the instruction UnbalancedInstruction /// Program illegally modified an account's program id ModifiedProgramId /// Program spent the lamports of an account that doesn't belong to it ExternalAccountLamportSpend /// Program modified the data of an account that doesn't belong to it ExternalAccountDataModified /// Read-only account's lamports modified ReadonlyLamportChange /// Read-only account's data was modified ReadonlyDataModified /// An account was referenced more than once in a single instruction // Deprecated, instructions can now contain duplicate accounts DuplicateAccountIndex /// Executable bit on account changed, but shouldn't have ExecutableModified /// Rent_epoch account changed, but shouldn't have RentEpochModified /// The instruction expected additional account keys NotEnoughAccountKeys /// Program other than the account's owner changed the size of the account data AccountDataSizeChanged /// The instruction expected an executable account AccountNotExecutable /// Failed to borrow a reference to account data, already borrowed AccountBorrowFailed /// Account data has an outstanding reference after a program's execution InstructionAccountBorrowOutstanding /// The same account was multiply passed to an on-chain program's entrypoint, but the program /// modified them differently. A program can only modify one instance of the account because /// the runtime cannot determine which changes to pick or how to merge them if both are modified DuplicateAccountOutOfSync /// Allows on-chain programs to implement program-specific error types and see them returned /// by the Solana runtime. A program-specific error may be any type that is represented as /// or serialized to a u32 integer. Custom // Custom(u32), /// The return value from the program was invalid. Valid errors are either a defined builtin /// error value or a user-defined error in the lower 32 bits. InvalidError /// Executable account's data was modified ExecutableDataModified /// Executable account's lamports modified ExecutableLamportChange /// Executable accounts must be rent exempt ExecutableAccountNotRentExempt /// Unsupported program id UnsupportedProgramId /// Cross-program invocation call depth too deep CallDepth /// An account required by the instruction is missing MissingAccount /// Cross-program invocation reentrancy not allowed for this instruction ReentrancyNotAllowed /// Length of the seed is too long for address generation MaxSeedLengthExceeded /// Provided seeds do not result in a valid address InvalidSeeds /// Failed to reallocate account data of this length InvalidRealloc /// Computational budget exceeded ComputationalBudgetExceeded /// Cross-program invocation with unauthorized signer or writable account PrivilegeEscalation /// Failed to create program execution environment ProgramEnvironmentSetupFailure /// Program failed to complete ProgramFailedToComplete /// Program failed to compile ProgramFailedToCompile /// Account is immutable Immutable /// Incorrect authority provided IncorrectAuthority /// Failed to serialize or deserialize account data /// /// Warning: This error should never be emitted by the runtime. /// /// This error includes strings from the underlying 3rd party Borsh crate /// which can be dangerous because the error strings could change across /// Borsh versions. Only programs can use this error because they are /// consistent across Solana software versions. /// string values from this error should not be used in BorshIoError // BorshIoError(String) // An account does not have enough lamports to be rent-exempt AccountNotRentExempt /// Invalid account owner InvalidAccountOwner /// Program arithmetic overflowed ArithmeticOverflow /// Unsupported sysvar UnsupportedSysvar /// Illegal account owner IllegalOwner /// Accounts data allocations exceeded the maximum allowed per transaction MaxAccountsDataAllocationsExceeded /// Max accounts exceeded MaxAccountsExceeded /// Max instruction trace length exceeded MaxInstructionTraceLengthExceeded /// Builtin programs must consume compute units BuiltinProgramsMustConsumeComputeUnits ) type TransactionError struct { Variant TransactionErrorVariant rest []byte } var ( ErrInvalidTransactionError = errors.New("invalid transaction error") NotAnInstructionError = errors.New("not an instruction error") NotACustomInstructionError = errors.New("not a custom instruction error") UnsupportedInstructionError = errors.New("unsupported instruction error") ) func DecodeTransactionError(data []byte) (*TransactionError, error) { if len(data) < 4 { return nil, ErrInvalidTransactionError } var err TransactionError variant := binary.LittleEndian.Uint32(data[:4]) if variant > uint32(CommitCancelled) { return nil, UnsupportedInstructionError } err.Variant = TransactionErrorVariant(variant) err.rest = data[4:] return &err, nil } func (e *TransactionError) GetCustomErrorCode() (uint8, uint32, error) { instr, err := e.GetInstructionError() if err != nil { return 0, 0, err } custom, err := instr.Custom() if err != nil { return 0, 0, err } return instr.Index, custom.Code, nil } func (e *TransactionError) GetInstructionError() (*InstructionErrorEnum, error) { if e.Variant != InstructionError { return nil, NotAnInstructionError } if len(e.rest) < 5 { return nil, NotAnInstructionError } var err InstructionErrorEnum err.Index = e.rest[0] variant := binary.LittleEndian.Uint32(e.rest[1:5]) if variant > uint32(BuiltinProgramsMustConsumeComputeUnits) { return nil, UnsupportedInstructionError } err.Variant = InstructionErrorVariant(binary.LittleEndian.Uint32(e.rest[1:5])) err.rest = e.rest[5:] return &err, nil } func (e *InstructionErrorEnum) Custom() (*CustomInstructionErrorEnum, error) { if e.Variant != Custom { return nil, NotACustomInstructionError } if len(e.rest) < 4 { return nil, NotACustomInstructionError } var custom CustomInstructionErrorEnum custom.Code = binary.LittleEndian.Uint32(e.rest[:4]) return &custom, nil }