{"record":{"id":"46aff50477cd0402","repo":"canopy-network/canopy","slug":"errinvaliderc20tx","errorCode":"ErrInvalidERC20Tx","errorMessage":"data too short","messagePattern":"data too short","errorType":"error_code","errorClass":"ErrInvalidERC20Tx","httpStatus":null,"severity":"error","filePath":"fsm/ethereum.go","lineNumber":178,"sourceCode":"\t\treturn tx.GasPrice(), nil\n\t}\n}\n\n// rlpToMessage() converts an ethereum RLP transaction to a message\nfunc rlpToMessage(publicKey crypto.PublicKeyI, transaction *lib.Transaction, tx ethTypes.Transaction) (msg lib.MessageI, e lib.ErrorI) {\n\t// get the relevant tx fields\n\tto, from, data := tx.To(), publicKey.Address().Bytes(), tx.Data()\n\t// ensure non-nil to\n\tif to == nil {\n\t\treturn nil, ErrRecipientAddressEmpty()\n\t}\n\t// switch on the 'recipient'\n\tswitch tx.To().Hex() {\n\t// if the recipient is a pseudo-contract call\n\tcase CNPYContractAddress, StakedCNPYContractAddress, SwapCNPYContractAddress:\n\t\t// ensure enough data for a selector\n\t\tif len(data) < 4 {\n\t\t\treturn nil, ErrInvalidERC20Tx(fmt.Errorf(\"data too short\"))\n\t\t}\n\t\t// switch on the selector\n\t\tswitch selector := lib.BytesToString(data[:4]); selector {\n\t\tcase SendSelector:\n\t\t\tmsg, e = ethDataToMsgSend(from, data)\n\t\tcase StakeSelector:\n\t\t\tm := new(MessageStake)\n\t\t\tmsg, e = ethDataToMsg(MessageStakeName, transaction, m, data, func() {\n\t\t\t\t// allow the omission of the public key because it may be difficult to get the public key from the wallet\n\t\t\t\tif len(m.PublicKey) == 0 {\n\t\t\t\t\tm.PublicKey = publicKey.Bytes()\n\t\t\t\t}\n\t\t\t})\n\t\tcase EditStakeSelector:\n\t\t\tm := new(MessageEditStake)\n\t\t\tmsg, e = ethDataToMsg(MessageEditStakeName, transaction, m, data, nil)\n\t\tcase UnstakeSelector:\n\t\t\tm := new(MessageUnstake)","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/fsm/ethereum.go#L160-L196","documentation":"When the RLP tx targets one of the pseudo-contract addresses, its calldata must at least contain the 4-byte ABI selector. rlpToMessage returns ErrInvalidERC20Tx('data too short') when the data is shorter than 4 bytes.","triggerScenarios":"Sending an RLP transaction to CNPYContractAddress, StakedCNPYContractAddress, or SwapCNPYContractAddress with empty or <4-byte tx.Data() — e.g. a plain value transfer addressed to the pseudo-contract.","commonSituations":"A wallet/user sending ETH-style value directly to the CNG contract address instead of calling transfer() with ABI-encoded calldata, or a bridge truncating the calldata.","solutions":["ABI-encode the intended call (selector + parameters) into the tx data field before signing","Do not send bare value transfers to the pseudo-contract addresses; use the proper transfer/selector call","Fix the bridging tool so it forwards the full calldata"],"exampleFix":"// before\ndata := []byte{} // bare send to pseudo-contract\n// after\nselector := crypto.Keccak256(\"transfer(address,uint256)\")[:4]\ndata := append(selector, abiEncodePacked(recipient, amount)...)","handlingStrategy":"validation","validationCode":"if tx.To() != nil && isPseudoContract(tx.To()) && len(tx.Data()) < 4 {\n    return fmt.Errorf(\"pseudo-contract calls need >= 4 byte selector; got %d\", len(tx.Data()))\n}","typeGuard":"func hasSelector(data []byte) bool { return len(data) >= 4 }","tryCatchPattern":"msg, err := fsm.RLPToCanopyTransaction(bz)\nif err != nil && strings.Contains(err.Error(), \"data too short\") {\n    return nil, fmt.Errorf(\"ABI-encode the pseudo-contract call before signing\")\n}","preventionTips":["Never send bare value to pseudo-contract addresses","Always ABI-encode selector + args","Test payloads with an ABI encoder before signing"],"tags":["abi","erc20","calldata","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}