diff --git a/crypto/enums/abi_function.py b/crypto/enums/abi_function.py index 7d8f14c..ae447df 100644 --- a/crypto/enums/abi_function.py +++ b/crypto/enums/abi_function.py @@ -8,3 +8,5 @@ class AbiFunction(Enum): USERNAME_RESIGNATION = 'resignUsername' VALIDATOR_REGISTRATION = 'registerValidator' VALIDATOR_RESIGNATION = 'resignValidator' + UPDATE_VALIDATOR = 'updateValidator' + TRANSFER = 'transfer' diff --git a/crypto/enums/contract_abi_type.py b/crypto/enums/contract_abi_type.py index 36d1795..e4872fa 100644 --- a/crypto/enums/contract_abi_type.py +++ b/crypto/enums/contract_abi_type.py @@ -4,4 +4,5 @@ class ContractAbiType(Enum): CUSTOM = 'custom' CONSENSUS = 'consensus' MULTIPAYMENT = 'multipayment' + TOKEN = 'token' USERNAMES = 'usernames' diff --git a/crypto/transactions/builder/token_transfer_builder.py b/crypto/transactions/builder/token_transfer_builder.py new file mode 100644 index 0000000..8c3b943 --- /dev/null +++ b/crypto/transactions/builder/token_transfer_builder.py @@ -0,0 +1,27 @@ +from crypto.enums.abi_function import AbiFunction +from crypto.enums.contract_abi_type import ContractAbiType +from crypto.transactions.builder.abstract_transaction_builder import ( + AbstractTransactionBuilder, +) +from crypto.transactions.types.evm_call import EvmCall +from crypto.utils.abi_encoder import AbiEncoder +from crypto.utils.transaction_utils import TransactionUtils + + +class TokenTransferBuilder(AbstractTransactionBuilder): + def contract_address(self, address): + self.transaction.data['to'] = address + return self + + def recipient(self, address, amount): + encoder = AbiEncoder(ContractAbiType.TOKEN) + payload = encoder.encode_function_call( + AbiFunction.TRANSFER.value, [address, amount] + ) + self.transaction.data['data'] = TransactionUtils.parse_hex_from_str( + payload + ) + return self + + def get_transaction_instance(self, data): + return EvmCall(data) diff --git a/crypto/utils/abi/json/Abi.Token.json b/crypto/utils/abi/json/Abi.Token.json new file mode 100644 index 0000000..854420b --- /dev/null +++ b/crypto/utils/abi/json/Abi.Token.json @@ -0,0 +1,345 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TOKEN", + "sourceName": "*/TOKEN.sol", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "recipients", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "batchTransfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b506040518060400160405280600681526020017f4441524b323000000000000000000000000000000000000000000000000000008152506040518060400160405280600681526020017f4441524b32300000000000000000000000000000000000000000000000000000815250816003908161008c91906105bc565b50806004908161009c91906105bc565b5050506100ba336a52b7d2dcc80cd2e40000006100bf60201b60201c565b6107ae565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101315760006040517fec442f0500000000000000000000000000000000000000000000000000000000815260040161012891906106cf565b60405180910390fd5b6101436000838361014760201b60201c565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361019957806002600082825461018d9190610719565b9250508190555061026c565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610225578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161021c9392919061075c565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036102b55780600260008282540392505081905550610302565b806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161035f9190610793565b60405180910390a3505050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806103ed57607f821691505b602082108103610400576103ff6103a6565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026104687fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261042b565b610472868361042b565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006104b96104b46104af8461048a565b610494565b61048a565b9050919050565b6000819050919050565b6104d38361049e565b6104e76104df826104c0565b848454610438565b825550505050565b600090565b6104fc6104ef565b6105078184846104ca565b505050565b5b8181101561052b576105206000826104f4565b60018101905061050d565b5050565b601f8211156105705761054181610406565b61054a8461041b565b81016020851015610559578190505b61056d6105658561041b565b83018261050c565b50505b505050565b600082821c905092915050565b600061059360001984600802610575565b1980831691505092915050565b60006105ac8383610582565b9150826002028217905092915050565b6105c58261036c565b67ffffffffffffffff8111156105de576105dd610377565b5b6105e882546103d5565b6105f382828561052f565b600060209050601f8311600181146106265760008415610614578287015190505b61061e85826105a0565b865550610686565b601f19841661063486610406565b60005b8281101561065c57848901518255600182019150602085019450602081019050610637565b868310156106795784890151610675601f891682610582565b8355505b6001600288020188555050505b505050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006106b98261068e565b9050919050565b6106c9816106ae565b82525050565b60006020820190506106e460008301846106c0565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006107248261048a565b915061072f8361048a565b9250828201905080821115610747576107466106ea565b5b92915050565b6107568161048a565b82525050565b600060608201905061077160008301866106c0565b61077e602083018561074d565b61078b604083018461074d565b949350505050565b60006020820190506107a8600083018461074d565b92915050565b611156806107bd6000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806370a082311161006657806370a082311461015d57806388d695b21461018d57806395d89b41146101bd578063a9059cbb146101db578063dd62ed3e1461020b5761009e565b806306fdde03146100a3578063095ea7b3146100c157806318160ddd146100f157806323b872dd1461010f578063313ce5671461013f575b600080fd5b6100ab61023b565b6040516100b89190610ba8565b60405180910390f35b6100db60048036038101906100d69190610c68565b6102cd565b6040516100e89190610cc3565b60405180910390f35b6100f96102f0565b6040516101069190610ced565b60405180910390f35b61012960048036038101906101249190610d08565b6102fa565b6040516101369190610cc3565b60405180910390f35b610147610329565b6040516101549190610d77565b60405180910390f35b61017760048036038101906101729190610d92565b610332565b6040516101849190610ced565b60405180910390f35b6101a760048036038101906101a29190610e7a565b61037a565b6040516101b49190610cc3565b60405180910390f35b6101c561043e565b6040516101d29190610ba8565b60405180910390f35b6101f560048036038101906101f09190610c68565b6104d0565b6040516102029190610cc3565b60405180910390f35b61022560048036038101906102209190610efb565b6104f3565b6040516102329190610ced565b60405180910390f35b60606003805461024a90610f6a565b80601f016020809104026020016040519081016040528092919081815260200182805461027690610f6a565b80156102c35780601f10610298576101008083540402835291602001916102c3565b820191906000526020600020905b8154815290600101906020018083116102a657829003601f168201915b5050505050905090565b6000806102d861057a565b90506102e5818585610582565b600191505092915050565b6000600254905090565b60008061030561057a565b9050610312858285610594565b61031d858585610628565b60019150509392505050565b60006012905090565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60008282905085859050146103c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103bb9061100d565b60405180910390fd5b60005b85859050811015610431576104246103dd61057a565b8787848181106103f0576103ef61102d565b5b90506020020160208101906104059190610d92565b8686858181106104185761041761102d565b5b90506020020135610628565b80806001019150506103c7565b5060019050949350505050565b60606004805461044d90610f6a565b80601f016020809104026020016040519081016040528092919081815260200182805461047990610f6a565b80156104c65780601f1061049b576101008083540402835291602001916104c6565b820191906000526020600020905b8154815290600101906020018083116104a957829003601f168201915b5050505050905090565b6000806104db61057a565b90506104e8818585610628565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b61058f838383600161071c565b505050565b60006105a084846104f3565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106225781811015610612578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016106099392919061106b565b60405180910390fd5b6106218484848403600061071c565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361069a5760006040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161069191906110a2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361070c5760006040517fec442f0500000000000000000000000000000000000000000000000000000000815260040161070391906110a2565b60405180910390fd5b6107178383836108f3565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361078e5760006040517fe602df0500000000000000000000000000000000000000000000000000000000815260040161078591906110a2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108005760006040517f94280d620000000000000000000000000000000000000000000000000000000081526004016107f791906110a2565b60405180910390fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080156108ed578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516108e49190610ced565b60405180910390a35b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361094557806002600082825461093991906110ec565b92505081905550610a18565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109d1578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016109c89392919061106b565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a615780600260008282540392505081905550610aae565b806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610b0b9190610ced565b60405180910390a3505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610b52578082015181840152602081019050610b37565b60008484015250505050565b6000601f19601f8301169050919050565b6000610b7a82610b18565b610b848185610b23565b9350610b94818560208601610b34565b610b9d81610b5e565b840191505092915050565b60006020820190508181036000830152610bc28184610b6f565b905092915050565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bff82610bd4565b9050919050565b610c0f81610bf4565b8114610c1a57600080fd5b50565b600081359050610c2c81610c06565b92915050565b6000819050919050565b610c4581610c32565b8114610c5057600080fd5b50565b600081359050610c6281610c3c565b92915050565b60008060408385031215610c7f57610c7e610bca565b5b6000610c8d85828601610c1d565b9250506020610c9e85828601610c53565b9150509250929050565b60008115159050919050565b610cbd81610ca8565b82525050565b6000602082019050610cd86000830184610cb4565b92915050565b610ce781610c32565b82525050565b6000602082019050610d026000830184610cde565b92915050565b600080600060608486031215610d2157610d20610bca565b5b6000610d2f86828701610c1d565b9350506020610d4086828701610c1d565b9250506040610d5186828701610c53565b9150509250925092565b600060ff82169050919050565b610d7181610d5b565b82525050565b6000602082019050610d8c6000830184610d68565b92915050565b600060208284031215610da857610da7610bca565b5b6000610db684828501610c1d565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610de457610de3610dbf565b5b8235905067ffffffffffffffff811115610e0157610e00610dc4565b5b602083019150836020820283011115610e1d57610e1c610dc9565b5b9250929050565b60008083601f840112610e3a57610e39610dbf565b5b8235905067ffffffffffffffff811115610e5757610e56610dc4565b5b602083019150836020820283011115610e7357610e72610dc9565b5b9250929050565b60008060008060408587031215610e9457610e93610bca565b5b600085013567ffffffffffffffff811115610eb257610eb1610bcf565b5b610ebe87828801610dce565b9450945050602085013567ffffffffffffffff811115610ee157610ee0610bcf565b5b610eed87828801610e24565b925092505092959194509250565b60008060408385031215610f1257610f11610bca565b5b6000610f2085828601610c1d565b9250506020610f3185828601610c1d565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610f8257607f821691505b602082108103610f9557610f94610f3b565b5b50919050565b7f726563697069656e747320616e6420616d6f756e7473206c656e677468206d6960008201527f736d617463680000000000000000000000000000000000000000000000000000602082015250565b6000610ff7602683610b23565b915061100282610f9b565b604082019050919050565b6000602082019050818103600083015261102681610fea565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b61106581610bf4565b82525050565b6000606082019050611080600083018661105c565b61108d6020830185610cde565b61109a6040830184610cde565b949350505050565b60006020820190506110b7600083018461105c565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006110f782610c32565b915061110283610c32565b925082820190508082111561111a576111196110bd565b5b9291505056fea2646970667358221220fdbfd2ff5d7f60018cd1ba9f99f9038e758419b539d4a76b8c9148f3b4c10b6b64736f6c634300081a0033" +} diff --git a/crypto/utils/abi_base.py b/crypto/utils/abi_base.py index f557a25..c113ddd 100644 --- a/crypto/utils/abi_base.py +++ b/crypto/utils/abi_base.py @@ -65,6 +65,9 @@ def __contract_abi_path(self, abi_type: ContractAbiType, path: Optional[str] = N if abi_type == ContractAbiType.MULTIPAYMENT: return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Multipayment.json') + if abi_type == ContractAbiType.TOKEN: + return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Token.json') + if abi_type == ContractAbiType.USERNAMES: return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Usernames.json') diff --git a/crypto/utils/abi_encoder.py b/crypto/utils/abi_encoder.py index 69dfdc2..c14fff5 100644 --- a/crypto/utils/abi_encoder.py +++ b/crypto/utils/abi_encoder.py @@ -13,6 +13,12 @@ def encode_function_call(self, function_name, args=[]): } return self.encode_function_data(parameters) + def encode_function_call_hex(self, function_name, args=[]): + result = self.encode_function_call(function_name, args) + if not result.startswith('0x'): + return '0x' + result + return result + def encode_function_data(self, parameters): args = parameters.get('args', []) diff --git a/crypto/utils/transaction_data_encoder.py b/crypto/utils/transaction_data_encoder.py new file mode 100644 index 0000000..1a99f5a --- /dev/null +++ b/crypto/utils/transaction_data_encoder.py @@ -0,0 +1,65 @@ +from crypto.enums.abi_function import AbiFunction +from crypto.enums.contract_abi_type import ContractAbiType +from crypto.utils.abi_encoder import AbiEncoder + + +class TransactionDataEncoder: + @staticmethod + def multi_payment(recipients, amounts): + return AbiEncoder(ContractAbiType.MULTIPAYMENT).encode_function_call_hex( + AbiFunction.MULTIPAYMENT.value, [recipients, amounts] + ) + + @staticmethod + def update_validator(validator_public_key): + key = validator_public_key + if not key.startswith('0x'): + key = '0x' + key + return AbiEncoder(ContractAbiType.CONSENSUS).encode_function_call_hex( + AbiFunction.UPDATE_VALIDATOR.value, [key] + ) + + @staticmethod + def username_registration(username): + return AbiEncoder(ContractAbiType.USERNAMES).encode_function_call_hex( + AbiFunction.USERNAME_REGISTRATION.value, [username] + ) + + @staticmethod + def username_resignation(): + return AbiEncoder(ContractAbiType.USERNAMES).encode_function_call_hex( + AbiFunction.USERNAME_RESIGNATION.value, [] + ) + + @staticmethod + def validator_registration(validator_public_key): + key = validator_public_key + if not key.startswith('0x'): + key = '0x' + key + return AbiEncoder(ContractAbiType.CONSENSUS).encode_function_call_hex( + AbiFunction.VALIDATOR_REGISTRATION.value, [key] + ) + + @staticmethod + def validator_resignation(): + return AbiEncoder(ContractAbiType.CONSENSUS).encode_function_call_hex( + AbiFunction.VALIDATOR_RESIGNATION.value, [] + ) + + @staticmethod + def token_transfer(recipient_address, amount): + return AbiEncoder(ContractAbiType.TOKEN).encode_function_call_hex( + AbiFunction.TRANSFER.value, [recipient_address, amount] + ) + + @staticmethod + def vote(vote_address): + return AbiEncoder(ContractAbiType.CONSENSUS).encode_function_call_hex( + AbiFunction.VOTE.value, [vote_address] + ) + + @staticmethod + def unvote(): + return AbiEncoder(ContractAbiType.CONSENSUS).encode_function_call_hex( + AbiFunction.UNVOTE.value, [] + ) diff --git a/tests/fixtures/transactions/token-transfer.json b/tests/fixtures/transactions/token-transfer.json new file mode 100644 index 0000000..b92a46c --- /dev/null +++ b/tests/fixtures/transactions/token-transfer.json @@ -0,0 +1,16 @@ +{ + "data": { + "value": "0", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "gasPrice": "5000000000", + "gasLimit": "21000", + "nonce": "1", + "data": "a9059cbb0000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb220000000000000000000000000000000000000000000000000000000000000000", + "to": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", + "v": 0, + "r": "ca5516c582647a1626bfeb4ccf62314dae02c8c561dbff690bdbda89d181e6f7", + "s": "1b4ddf55e432e532c8e8d1a854f21e0c80e35a35fe4557899fb3f485d071f1e1", + "hash": "4bb567e6ffd6716b99865fc6917eadf0f5b6cbccdd6999a592db6143a7f24d81" + }, + "serialized": "f8ab0185012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb2280b844a9059cbb0000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb220000000000000000000000000000000000000000000000000000000000000000825c6ba0ca5516c582647a1626bfeb4ccf62314dae02c8c561dbff690bdbda89d181e6f7a01b4ddf55e432e532c8e8d1a854f21e0c80e35a35fe4557899fb3f485d071f1e1" +} diff --git a/tests/fixtures/transactions/transaction-data-encoder.json b/tests/fixtures/transactions/transaction-data-encoder.json new file mode 100644 index 0000000..2cc9fcd --- /dev/null +++ b/tests/fixtures/transactions/transaction-data-encoder.json @@ -0,0 +1,15 @@ +{ + "Username": "test", + "Address": "0xA5cc0BfEB09742C5e4C610f2EBaaB82Eb142Ca10", + "ValidatorPublicKey": "b209f4a7454ae17c5808991dffbf204c747b851f351d2ce72a6e18903d0e2f609e0328ebbc3fb97cd4d3660b4bc156f1", + "Amount": "1000000000000", + "Encoded": { + "UpdateValidator": "0x5a8eed7300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030b209f4a7454ae17c5808991dffbf204c747b851f351d2ce72a6e18903d0e2f609e0328ebbc3fb97cd4d3660b4bc156f100000000000000000000000000000000", + "UsernameRegistration": "0x36a94134000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", + "UsernameResignation": "0xebed6dab", + "ValidatorRegistration": "0x602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030b209f4a7454ae17c5808991dffbf204c747b851f351d2ce72a6e18903d0e2f609e0328ebbc3fb97cd4d3660b4bc156f100000000000000000000000000000000", + "ValidatorResignation": "0xb85f5da2", + "TokenTransfer": "0xa9059cbb000000000000000000000000a5cc0bfeb09742c5e4c610f2ebaab82eb142ca10000000000000000000000000000000000000000000000000000000e8d4a51000", + "MultiPayment": "0x084ce708000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc0bfeb09742c5e4c610f2ebaab82eb142ca10000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e8" + } +} diff --git a/tests/transactions/builder/test_token_transfer_builder.py b/tests/transactions/builder/test_token_transfer_builder.py new file mode 100644 index 0000000..376b8a3 --- /dev/null +++ b/tests/transactions/builder/test_token_transfer_builder.py @@ -0,0 +1,53 @@ +from crypto.transactions.builder.token_transfer_builder import ( + TokenTransferBuilder, +) + + +def test_token_transfer_transaction(passphrase, load_transaction_fixture): + fixture = load_transaction_fixture('transactions/token-transfer') + + builder = ( + TokenTransferBuilder + .new() + .recipient(fixture['data']['to'], int(fixture['data']['value'])) + .to(fixture['data']['to']) + .nonce(fixture['data']['nonce']) + .gas_price(fixture['data']['gasPrice']) + .gas_limit(fixture['data']['gasLimit']) + .sign(passphrase) + ) + + assert builder.transaction.data['gasPrice'] == int( + fixture['data']['gasPrice'] + ) + assert builder.transaction.data['gasLimit'] == int( + fixture['data']['gasLimit'] + ) + assert builder.transaction.data['nonce'] == fixture['data']['nonce'] + assert builder.transaction.data['to'].lower() == ( + fixture['data']['to'].lower() + ) + assert builder.transaction.data['v'] == fixture['data']['v'] + assert builder.transaction.data['r'] == fixture['data']['r'] + assert builder.transaction.data['s'] == fixture['data']['s'] + assert builder.transaction.data['hash'] == fixture['data']['hash'] + + assert builder.verify() + + +def test_token_transfer_serialization(passphrase, load_transaction_fixture): + fixture = load_transaction_fixture('transactions/token-transfer') + + builder = ( + TokenTransferBuilder + .new() + .recipient(fixture['data']['to'], int(fixture['data']['value'])) + .to(fixture['data']['to']) + .nonce(fixture['data']['nonce']) + .gas_price(fixture['data']['gasPrice']) + .gas_limit(fixture['data']['gasLimit']) + .sign(passphrase) + ) + + serialized = builder.transaction.serialize().hex() + assert serialized == fixture['serialized'] diff --git a/tests/utils/test_abi_base.py b/tests/utils/test_abi_base.py index 0705883..124c275 100644 --- a/tests/utils/test_abi_base.py +++ b/tests/utils/test_abi_base.py @@ -1,6 +1,19 @@ +from crypto.enums.contract_abi_type import ContractAbiType from crypto.utils.abi_base import AbiBase +def test_it_should_load_token_abi(): + abi_base = AbiBase(ContractAbiType.TOKEN) + function_names = [ + item['name'] for item in abi_base.abi if item.get('type') == 'function' + ] + assert 'transfer' in function_names + assert 'approve' in function_names + assert 'balanceOf' in function_names + assert 'totalSupply' in function_names + assert 'allowance' in function_names + + def test_it_should_validate_uppercase_addresses(): assert AbiBase().is_valid_address('0xC3bBE9B1CeE1ff85Ad72b87414B0E9B7F2366763') is True diff --git a/tests/utils/test_abi_decoder.py b/tests/utils/test_abi_decoder.py index e5b59cc..369563b 100644 --- a/tests/utils/test_abi_decoder.py +++ b/tests/utils/test_abi_decoder.py @@ -1,3 +1,4 @@ +from crypto.enums.contract_abi_type import ContractAbiType from crypto.utils.abi_decoder import AbiDecoder @@ -13,3 +14,18 @@ def test_decode_vote_payload(): 'functionName': function_name, 'args': args, } + + +def test_decode_token_transfer(): + decoder = AbiDecoder(ContractAbiType.TOKEN) + data = ( + '0xa9059cbb' + '000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763' + '00000000000000000000000000000000000000000000000000000000000003e8' + ) + decoded = decoder.decode_function_data(data) + assert decoded['functionName'] == 'transfer' + assert decoded['args'] == [ + '0xC3bBE9B1CeE1ff85Ad72b87414B0E9B7F2366763', + 1000, + ] diff --git a/tests/utils/test_abi_encoder.py b/tests/utils/test_abi_encoder.py index 96f6053..c1e8749 100644 --- a/tests/utils/test_abi_encoder.py +++ b/tests/utils/test_abi_encoder.py @@ -1,3 +1,4 @@ +from crypto.enums.contract_abi_type import ContractAbiType from crypto.utils.abi_encoder import AbiEncoder @@ -22,3 +23,17 @@ def test_encode_address(): 'dynamic': False, 'encoded': '0x000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763', } + + +def test_encode_token_transfer(): + encoder = AbiEncoder(ContractAbiType.TOKEN) + encoded = encoder.encode_function_call( + 'transfer', + ['0xC3bBE9B1CeE1ff85Ad72b87414B0E9B7F2366763', 1000] + ) + expected = ( + '0xa9059cbb' + '000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763' + '00000000000000000000000000000000000000000000000000000000000003e8' + ) + assert encoded == expected diff --git a/tests/utils/test_transaction_data_encoder.py b/tests/utils/test_transaction_data_encoder.py new file mode 100644 index 0000000..90ae662 --- /dev/null +++ b/tests/utils/test_transaction_data_encoder.py @@ -0,0 +1,43 @@ +from crypto.utils.transaction_data_encoder import TransactionDataEncoder + + +def test_encode_token_transfer(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.token_transfer( + fixture['Address'], fixture['Amount'] + ) + assert encoded == fixture['Encoded']['TokenTransfer'] + + +def test_encode_username_registration(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.username_registration(fixture['Username']) + assert encoded == fixture['Encoded']['UsernameRegistration'] + + +def test_encode_username_resignation(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.username_resignation() + assert encoded == fixture['Encoded']['UsernameResignation'] + + +def test_encode_validator_registration(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.validator_registration( + fixture['ValidatorPublicKey'] + ) + assert encoded == fixture['Encoded']['ValidatorRegistration'] + + +def test_encode_validator_resignation(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.validator_resignation() + assert encoded == fixture['Encoded']['ValidatorResignation'] + + +def test_encode_multi_payment(load_transaction_fixture): + fixture = load_transaction_fixture('transactions/transaction-data-encoder') + encoded = TransactionDataEncoder.multi_payment( + [fixture['Address']], ['1000'] + ) + assert encoded == fixture['Encoded']['MultiPayment']