def to_dictionary_as_inner(self) -> Dict[str, Any]: dictionary = self.to_dictionary() dictionary["receiver"] = base64.b64encode(Address(self.receiver).pubkey()).decode() dictionary["sender"] = base64.b64encode(Address(self.sender).pubkey()).decode() dictionary["chainID"] = base64.b64encode(self.chainID.encode()).decode() dictionary["signature"] = base64.b64encode(bytes(bytearray.fromhex(self.signature))).decode() dictionary["value"] = int(self.value) return dictionary
def prepare_args_for_change_reward_address(args: Any): reward_address = Address(args.reward_address) args.data = 'changeRewardAddress@' + reward_address.hex() args.receiver = AUCTION_SMART_CONTRACT_ADDRESS if args.estimate_gas: args.gas_limit = estimate_system_sc_call(args, MetaChainSystemSCsCost.CHANGE_REWARD_ADDRESS)
def _get_sc_address_from_tx(data: Any): if not isinstance(data, dict): raise errors.ProgrammingError("error") sc_results = data.get('smartContractResults') if sc_results is None: raise errors.ProgrammingError("smart contract results missing") # TODO improve robustness of this code in case of failed transaction try: sc_result = sc_results[0] data_field = sc_result['data'] data_field_split = data_field.split('@') arg_1 = binascii.unhexlify(data_field_split[1]) if not arg_1 == b'ok': raise errors.ProgrammingError(arg_1.decode("utf-8")) sc_address = binascii.unhexlify(data_field_split[2]) address = Address(sc_address) print("Contract address: ", address) except: raise errors.ProgrammingError( "cannot get the smart contract address from transaction results, please try again" )
def parse_args_for_stake(args): num_of_nodes = int(args.number_of_nodes) keys = args.nodes_public_keys.split(',') if num_of_nodes != len(keys): logger.info( "number of nodes is not equals with number of provided validators keys" ) return reward_address = args.reward_address stake_data = 'stake@' + binascii.hexlify( num_of_nodes.to_bytes(1, byteorder="little")).decode() for key in keys: stake_data += '@' + key + '@' + convert_to_hex('genesis') if reward_address: reward_address = Address(args.reward_address) stake_data += '@' + reward_address.hex() args.receiver = _STAKE_SMART_CONTRACT_ADDRESS args.data = stake_data if args.estimate_gas: args.gas_limit = estimate_system_sc_call(args, MetaChainSystemSCsCost.STAKE, len(keys)) return args
def prepare_args_for_stake(args: Any): validators_file = ValidatorsFile(args.validators_file) reward_address = args.reward_address # TODO: Refactor, so that only address is received here. if args.pem: account = Account(pem_file=args.pem) elif args.keyfile and args.passfile: account = Account(key_file=args.keyfile, pass_file=args.passfile) num_of_nodes = validators_file.get_num_of_nodes() stake_data = 'stake@' + binascii.hexlify(num_of_nodes.to_bytes(1, byteorder="little")).decode() validators_list = validators_file.get_validators_list() for validator in validators_list: # get validator validator_pem = validator.get("pemFile") validator_pem = path.join(path.dirname(args.validators_file), validator_pem) seed, bls_key = parse_validator_pem(validator_pem) signed_message = sign_message_with_bls_key(account.address.pubkey().hex(), seed.hex()) stake_data += f"@{bls_key}@{signed_message}" if reward_address: reward_address = Address(args.reward_address) stake_data += '@' + reward_address.hex() args.receiver = AUCTION_SMART_CONTRACT_ADDRESS args.data = stake_data if args.estimate_gas: args.gas_limit = estimate_system_sc_call(args, MetaChainSystemSCsCost.STAKE, num_of_nodes)
def get_account_transactions(args: Any): proxy_url = args.proxy address = args.address proxy = ElrondProxy(proxy_url) response = proxy.get_account_transactions(Address(address)) utils.dump_out_json(response, args.outfile)
def do_bech32(args): encode = args.encode value = args.value address = Address(value) result = address.bech32() if encode else address.hex() print(result) return result
def get_account_balance(args): proxy_url = args.proxy address = args.address proxy = ElrondProxy(proxy_url) balance = proxy.get_account_balance(Address(address)) print(balance) return balance
def get_account_transactions(args): proxy_url = args.proxy address = args.address proxy = ElrondProxy(proxy_url) account = proxy.get_account_transactions(Address(address)) print(account) return account
def resolve(name: str, proxy: ElrondProxy) -> Address: name_arg = "0x{}".format(str.encode(name).hex()) dns_address = dns_address_for_name(name) contract = SmartContract(dns_address) result = contract.query(proxy, "resolve", [name_arg]) if len(result) == 0: return Address.zero() return Address(result[0].hex)
def test_address(self): address = Address("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz") address_cloned = Address(address) self.assertEqual("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293", address.hex()) self.assertEqual("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", address.bech32()) self.assertEqual(address.hex(), address_cloned.hex()) self.assertEqual(address.bech32(), address_cloned.bech32()) address = Address("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293") address_cloned = Address(address) self.assertEqual("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293", address.hex()) self.assertEqual("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", address.bech32()) self.assertEqual(address.hex(), address_cloned.hex()) self.assertEqual(address.bech32(), address_cloned.bech32()) address = Address("") self.assertRaises(errors.EmptyAddressError, address.hex) self.assertRaises(errors.EmptyAddressError, address.bech32) address = Address(None) self.assertRaises(errors.EmptyAddressError, address.hex) self.assertRaises(errors.EmptyAddressError, address.bech32) with self.assertRaises(errors.BadAddressFormatError) as _: address = Address("bad")
def test_pem_parse_multiple(self): pem_file = self.testdata.joinpath("keys", "walletKey.pem") seed, address = pem.parse(pem_file, index=0) self.assertEqual("1f4dd8b7d18b5d0785c9d0802ec14d553dba356812b85c7e3414373388472010", seed.hex()) self.assertEqual(Address("erd1sjsk3n2d0krq3pyxxtgf0q7j3t56sgusqaujj4n82l39t9h7jers6gslr4").hex(), address.hex()) seed, address = pem.parse(pem_file, index=1) self.assertEqual("2565dbbdb62301e4c7b12b8a41cd3b2fbd7ae687c8d9741937aa48cf246aeb25", seed.hex()) self.assertEqual(Address("erd10536tc3s886yqxtln74u6mztuwl5gy9k9gp8fttxda0klgxg979srtg5wt").hex(), address.hex()) seed, address = pem.parse(pem_file, index=2) self.assertEqual("08de69d398f4a5ffdce0f1a8569704dbc8b58aaf7ba3e726134e32f1e8bf04ad", seed.hex()) self.assertEqual(Address("erd1n230jlgfepdvf28vqt3zeawexg2jhvxqxjuqdfsss0xc62xcqcps9k54ag").hex(), address.hex()) seed, address = pem.parse(pem_file, index=3) self.assertEqual("4d9dcc1c09a6d00c4c9a389e662d9fe26e0bf4c859776d4d338b5a9c41fc12d4", seed.hex()) self.assertEqual(Address("erd143907zxv0ujxr9q4mda7rmczn2xwhmqn7p9lfz666z8hd2lcks2szt5yql").hex(), address.hex())
def parse_args_for_changing_reward_address(args): reward_address = Address(args.reward_address) args.data = 'changeRewardAddress@' + reward_address.hex() args.receiver = _STAKE_SMART_CONTRACT_ADDRESS if args.estimate_gas: args.gas_limit = estimate_system_sc_call( args, MetaChainSystemSCsCost.CHANGE_REWARD_ADDRESS) return args
def compute_address(self): """ 8 bytes of zero + 2 bytes for VM type + 20 bytes of hash(owner) + 2 bytes of shard(owner) """ owner_bytes = self.owner.address.pubkey() nonce_bytes = self.owner.nonce.to_bytes(8, byteorder="little") bytes_to_hash = owner_bytes + nonce_bytes address = keccak.new(digest_bits=256).update(bytes_to_hash).digest() address = bytes([0] * 8) + bytes( [5, 0]) + address[10:30] + owner_bytes[30:] self.address = Address(address)
def generate_pem(args): pem_file = args.pem mnemonic = args.mnemonic seed, pubkey = wallet.generate_pair() if mnemonic: seed, pubkey = wallet.derive_keys(mnemonic) address = Address(pubkey) pem.write(pem_file, seed, pubkey, name=address.bech32()) logger.info(f"Created PEM file [{pem_file}] for [{address.bech32()}]")
def get_account(args: Any): proxy_url = args.proxy address = args.address proxy = ElrondProxy(proxy_url) account = proxy.get_account(Address(address)) if args.balance: print(account.get("balance", 0)) elif args.nonce: print(account.get("nonce", 0)) else: print(account)
def compute_dns_address_for_shard_id(shard_id) -> Address: deployer_pubkey_prefix = InitialDNSAddress[:len(InitialDNSAddress) - ShardIdentiferLen] deployer_pubkey = deployer_pubkey_prefix + bytes([0, shard_id]) deployer = Account(address=Address(deployer_pubkey)) deployer.nonce = 0 # Workaround: currently, in erdpy, in order to compute the address of a contract, one has to create an instance of the class "SmartContract". # This might change in the future. contract = SmartContract() contract.owner = deployer contract.compute_address() return contract.address
def get_account(args: Any): proxy_url = args.proxy address = args.address proxy = ElrondProxy(proxy_url) account = proxy.get_account(Address(address)) omit_fields = cli_shared.parse_omit_fields_arg(args) if args.balance: print(account.get("balance", 0)) elif args.nonce: print(account.get("nonce", 0)) else: utils.omit_fields(account, omit_fields) utils.dump_out_json(account)
def generate_pem(args: Any): pem_file = args.pem mnemonic = args.mnemonic index = args.index seed, pubkey = wallet.generate_pair() if mnemonic: mnemonic = input("Enter mnemonic:\n") mnemonic = mnemonic.strip() seed, pubkey = wallet.derive_keys(mnemonic, index) address = Address(pubkey) pem.write(pem_file, seed, pubkey, name=address.bech32()) logger.info(f"Created PEM file [{pem_file}] for [{address.bech32()}]")
def main(): logging.basicConfig(level=logging.DEBUG) parser = ArgumentParser() parser.add_argument("--proxy", default="https://testnet-api.elrond.com") parser.add_argument("--keyfile", help="wallet JSON keyfile", required=True) parser.add_argument("--passfile", help="wallet password file", required=True) parser.add_argument("--reward-address", required=True, help="the reward address") parser.add_argument("--validators-file", required=True, help="validators JSON file (with links to PEM files)") parser.add_argument("--value", required=True, help="the value to stake") args = parser.parse_args() args.estimate_gas = True args.pem = None proxy = ElrondProxy(args.proxy) network = proxy.get_network_config() args.chain = network.chain_id args.gas_price = network.min_gas_price args.version = network.min_tx_version print("Reward address:") print(Address(args.reward_address).bech32()) confirm_continuation() prepare_args_for_stake(args) print("Transaction data:") print(args.data) confirm_continuation() print("Elrond Proxy (or Observer) address:", args.proxy) print("Chain ID:", args.chain) confirm_continuation() print("Value to stake:") print(int(args.value) / int(math.pow(10, 18)), "ERD") confirm_continuation() node_operator = Account(key_file=args.keyfile, pass_file=args.passfile) node_operator.sync_nonce(proxy) args.nonce = node_operator.nonce tx = do_prepare_transaction(args) tx.dump_to(sys.stdout) print("Transaction will now be sent.") confirm_continuation() tx.send(proxy) print("Done.")
def do_prepare_transaction(args): # "sender" taken from the PEM file sender_bytes = pem.get_pubkey(args.pem) sender_bech32 = Address(sender_bytes).bech32() plain = PlainTransaction() plain.nonce = int(args.nonce) plain.value = args.value plain.sender = sender_bech32 plain.receiver = args.receiver plain.gasPrice = int(args.gas_price) plain.gasLimit = int(args.gas_limit) plain.data = args.data payload = TransactionPayloadToSign(plain) signature = signing.sign_transaction(payload, args.pem) prepared = PreparedTransaction(plain, signature) return prepared
def post_process_hyperblock(block: dict): # The timestamp can be computed deterministically, given the round and the genesis time round = int(block.get("round", 0)) block["timestamp"] = constants.ERD_START_TIME + constants.ERD_ROUND_TIME * round hyperblock_nonce = block.get("nonce") hyperblock_hash = block.get("hash") # Hyperblocks V1 does not provide the transaction fees (nor "gasUsed"). Hyperblocks V2 will provide this information. # Until then, we can compute the fees deterministically (best-effort). # For Smart Contract transactions, the refunds will be incompletely provided by the API - until Hyperblocks V2 becomes available. # (e.g. intra-shard refunds are not visible etc.) for transaction in block["transactions"]: tx_type = transaction.get("type") tx_gas_limit = int(transaction.get("gasLimit", 0)) tx_gas_price = int(transaction.get("gasPrice", 0)) tx_receiver = Address(transaction.get("receiver")) tx_data = transaction.get("data", None) tx_data_decoded = "" tx_data_len = 0 tx_gas_used = 0 if tx_data: tx_data_decoded = base64.b64decode(tx_data) tx_data_len = len(tx_data_decoded) if tx_type == "normal": if tx_receiver.is_contract_address(): tx_gas_used = tx_gas_limit else: tx_gas_used = constants.ERD_MIN_GAS_LIMIT + tx_data_len * constants.ERD_GAS_PER_DATA_BYTE fee = tx_gas_used * tx_gas_price transaction["fee"] = str(fee) # Also add the hyperblock coordinates, for convenience # (a bit of content duplication, since they are also provided in the parent structure): transaction["hyperblockNonce"] = hyperblock_nonce transaction["hyperblockHash"] = hyperblock_hash
def upgrade(args: Any): logger.debug("upgrade") cli_shared.check_broadcast_args(args) contract_address = args.contract arguments = args.arguments gas_price = args.gas_price gas_limit = args.gas_limit value = args.value chain = args.chain version = args.version contract = _prepare_contract(args) contract.address = Address(contract_address) sender = _prepare_sender(args) tx = contract.upgrade(sender, arguments, gas_price, gas_limit, value, chain, version) try: result = _send_or_simulate(tx, args) finally: txdict = tx.to_dump_dict() dump_tx_and_result(txdict, result, args)
def parse_args_for_stake(args: Any): validators_file = args.validators_file validators_data = _read_json_file(validators_file) reward_address = args.reward_address if args.pem: account = Account(pem_file=args.pem) elif args.keyfile and args.passfile: account = Account(key_file=args.keyfile, pass_file=args.passfile) num_of_nodes = len(validators_data.get("validators", [])) stake_data = 'stake@' + binascii.hexlify( num_of_nodes.to_bytes(1, byteorder="little")).decode() for validator in validators_data.get("validators", []): # get validator validator_pem = validator.get("pemFile") validator_pem = path.join(path.dirname(validators_file), validator_pem) seed, bls_key = parse_validator_pem(validator_pem) signed_message = sign_message_with_bls_key( account.address.pubkey().hex(), seed.hex()) stake_data += f"@{bls_key}@{signed_message}" if reward_address: reward_address = Address(args.reward_address) stake_data += '@' + reward_address.hex() args.receiver = _STAKE_SMART_CONTRACT_ADDRESS args.data = stake_data if args.estimate_gas: args.gas_limit = estimate_system_sc_call(args, MetaChainSystemSCsCost.STAKE, num_of_nodes) return args
def get_account_data(self, address: str) -> dict(): return self.CLIENT.get_account(Address(address))
def main(): logging.basicConfig(level=logging.DEBUG) parser = ArgumentParser() parser.add_argument("--proxy", default="https://testnet-api.elrond.com") parser.add_argument("--pem", required=True) parser.add_argument("--reward-address", required=True, help="the reward address") parser.add_argument("--nodes-file", required=True, help="file containing list of BLS keys, one per line") parser.add_argument("--value", required=True, help="the value to stake") args = parser.parse_args() proxy_url = args.proxy reward_address = Address(args.reward_address) lines = utils.read_lines(args.nodes_file) value = args.value chain = config.get_chain_id() print("Reward address:") print(reward_address.bech32()) confirm_continuation() print("Number of Nodes to stake:", len(lines)) confirm_continuation() for line in lines: print(line[:8], "...", line[-8:]) confirm_continuation() print("Elrond Proxy (or Observer) address:", proxy_url) print("Chain ID:", chain) confirm_continuation() print("Value to stake:") print(int(value)) print(int(value) / int(math.pow(10, 18)), "ERD") confirm_continuation() stake_args: Any = utils.Object() stake_args.reward_address = reward_address.bech32() stake_args.number_of_nodes = len(lines) # Minor programming artifice (the CSV formatting), # so that we are compatible with erdpy 0.7.2 (this will change in the future) stake_args.nodes_public_keys = ",".join(lines) stake_args.estimate_gas = True stake_args.gas_price = 1000000000 stake_args.value = args.value stake_args.pem = args.pem stake_args.proxy = proxy_url stake_args.chain = chain stake_args.version = config.get_tx_version() stake_args.recall_nonce = True print("Transaction will now be sent.") confirm_continuation() facade.prepare_and_send_stake_transaction(stake_args) print("Done.")
def __init__(self, address=None, bytecode=None, metadata=None): self.address = Address(address) self.bytecode = bytecode self.metadata = metadata or CodeMetadata()
def get_account_transactions(self, address) -> dict(): return self.CLIENT.get_account_transactions(Address(address))
def parse_item(item: str): parts = item.split(":") address = Address(parts[0]) value = int(float(parts[1]) * ONE_EGLD) return address, value