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 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 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 _build_user_entry(nickname: str, account: Account, value: int, delegated_value: int, delegation_address: Address): return { "nickname": nickname, "address": account.address.bech32(), "supply": str(value), "balance": str(value - delegated_value), "stakingvalue": "0", "delegation": { "address": delegation_address.bech32(), "value": str(delegated_value) } }
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()}]")
class SmartContract: def __init__(self, address=None, bytecode=None, metadata=None): self.address = Address(address) self.bytecode = bytecode self.metadata = metadata or CodeMetadata() def deploy(self, proxy, owner, arguments, gas_price, gas_limit, value): self.owner = owner self.owner.sync_nonce(proxy) self.compute_address() transaction = self.prepare_deploy_transaction(owner, arguments, gas_price, gas_limit, value) tx_hash = transaction.send(proxy) return tx_hash, self.address def prepare_deploy_transaction(self, owner, arguments, gas_price, gas_limit, value): arguments = arguments or [] gas_price = int(gas_price or config.DEFAULT_GAS_PRICE) gas_limit = int(gas_limit) value = str(value or "0") plain = PlainTransaction() plain.nonce = owner.nonce plain.value = value plain.sender = owner.address.bech32() plain.receiver = Address.zero().bech32() plain.gasPrice = gas_price plain.gasLimit = gas_limit plain.data = self.prepare_deploy_transaction_data(arguments) payload = TransactionPayloadToSign(plain) signature = signing.sign_transaction(payload, owner.pem_file) prepared = PreparedTransaction(plain, signature) return prepared def prepare_deploy_transaction_data(self, arguments): tx_data = f"{self.bytecode}@{VM_TYPE_ARWEN}@{self.metadata.to_hex()}" for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data 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 execute(self, proxy, caller, function, arguments, gas_price, gas_limit, value): self.caller = caller self.caller.sync_nonce(proxy) transaction = self.prepare_execute_transaction(caller, function, arguments, gas_price, gas_limit, value) tx_hash = transaction.send(proxy) return tx_hash def prepare_execute_transaction(self, caller, function, arguments, gas_price, gas_limit, value): arguments = arguments or [] gas_price = int(gas_price or config.DEFAULT_GAS_PRICE) gas_limit = int(gas_limit) value = str(value or "0") plain = PlainTransaction() plain.nonce = caller.nonce plain.value = value plain.sender = caller.address.bech32() plain.receiver = self.address.bech32() plain.gasPrice = gas_price plain.gasLimit = gas_limit plain.data = self.prepare_execute_transaction_data(function, arguments) payload = TransactionPayloadToSign(plain) signature = signing.sign_transaction(payload, caller.pem_file) prepared = PreparedTransaction(plain, signature) return prepared def prepare_execute_transaction_data(self, function, arguments): tx_data = function for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data def upgrade(self, proxy, caller, arguments, gas_price, gas_limit, value): self.caller = caller self.caller.sync_nonce(proxy) transaction = self.prepare_upgrade_transaction(caller, arguments, gas_price, gas_limit, value) tx_hash = transaction.send(proxy) return tx_hash def prepare_upgrade_transaction(self, owner, arguments, gas_price, gas_limit, value): arguments = arguments or [] gas_price = int(gas_price or config.DEFAULT_GAS_PRICE) gas_limit = int(gas_limit) value = str(value or "0") plain = PlainTransaction() plain.nonce = owner.nonce plain.value = value plain.sender = owner.address.bech32() plain.receiver = self.address.bech32() plain.gasPrice = gas_price plain.gasLimit = gas_limit plain.data = self.prepare_upgrade_transaction_data(arguments) payload = TransactionPayloadToSign(plain) signature = signing.sign_transaction(payload, owner.pem_file) prepared = PreparedTransaction(plain, signature) return prepared def prepare_upgrade_transaction_data(self, arguments): tx_data = f"upgradeContract@{self.bytecode}@{self.metadata.to_hex()}" for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data def query(self, proxy, function, arguments): arguments = arguments or [] prepared_arguments = [ _prepare_argument(argument) for argument in arguments ] # TODO: move to proxy/core.py? payload = { "ScAddress": self.address.bech32(), "FuncName": function, "Args": prepared_arguments } response = proxy.query_contract(payload) return response["data"]["ReturnData"]
class SmartContract: def __init__(self, address=None, bytecode=None, metadata=None): self.address = Address(address) self.bytecode = bytecode self.metadata = metadata or CodeMetadata() def deploy(self, owner, arguments, gas_price, gas_limit, value, chain, version) -> Transaction: self.owner = owner self.compute_address() arguments = arguments or [] gas_price = int(gas_price) gas_limit = int(gas_limit) value = str(value or "0") tx = Transaction() tx.nonce = owner.nonce tx.value = value tx.sender = owner.address.bech32() tx.receiver = Address.zero().bech32() tx.gasPrice = gas_price tx.gasLimit = gas_limit tx.data = self.prepare_deploy_transaction_data(arguments) tx.chainID = chain tx.version = version tx.sign(owner) return tx def prepare_deploy_transaction_data(self, arguments): tx_data = f"{self.bytecode}@{VM_TYPE_ARWEN}@{self.metadata.to_hex()}" for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data 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 execute(self, caller, function, arguments, gas_price, gas_limit, value, chain, version) -> Transaction: self.caller = caller arguments = arguments or [] gas_price = int(gas_price) gas_limit = int(gas_limit) value = str(value or "0") tx = Transaction() tx.nonce = caller.nonce tx.value = value tx.sender = caller.address.bech32() tx.receiver = self.address.bech32() tx.gasPrice = gas_price tx.gasLimit = gas_limit tx.data = self.prepare_execute_transaction_data(function, arguments) tx.chainID = chain tx.version = version tx.sign(caller) return tx def prepare_execute_transaction_data(self, function, arguments): tx_data = function for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data def upgrade(self, owner, arguments, gas_price, gas_limit, value, chain, version) -> Transaction: self.owner = owner arguments = arguments or [] gas_price = int(gas_price or config.DEFAULT_GAS_PRICE) gas_limit = int(gas_limit) value = str(value or "0") tx = Transaction() tx.nonce = owner.nonce tx.value = value tx.sender = owner.address.bech32() tx.receiver = self.address.bech32() tx.gasPrice = gas_price tx.gasLimit = gas_limit tx.data = self.prepare_upgrade_transaction_data(arguments) tx.chainID = chain tx.version = version tx.sign(owner) return tx def prepare_upgrade_transaction_data(self, arguments): tx_data = f"upgradeContract@{self.bytecode}@{self.metadata.to_hex()}" for arg in arguments: tx_data += f"@{_prepare_argument(arg)}" return tx_data def query(self, proxy, function, arguments) -> List[Any]: arguments = arguments or [] prepared_arguments = [ _prepare_argument(argument) for argument in arguments ] payload = { "ScAddress": self.address.bech32(), "FuncName": function, "Args": prepared_arguments } response = proxy.query_contract(payload) return_data = response.get("data", {}).get("returnData") return [self._interpret_return_data(data) for data in return_data] def _interpret_return_data(self, data): try: as_bytes = base64.b64decode(data) as_hex = as_bytes.hex() as_number = int(as_hex, 16) result = utils.Object() result.base64 = data result.hex = as_hex result.number = as_number return result except Exception: logger.warn(f"Cannot interpret return data: {data}") return None
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.")