def test_xrp_key_signature(): key = RippleKey(private_key='ssq55ueDob4yV3kPVnNQLHB6icwpC') data = {'Account': key.to_account()} # sign data with fixed k value for deterministic result signature = key.sign_tx(data, k=3) assert signature == ( b'0E\x02!\x00\xf90\x8a\x01\x92X\xc3\x10I4O\x85\xf8\x9dR)\xb51\xc8E' b'\x83o\x99\xb0\x86\x01\xf1\x13\xbc\xe06\xf9\x02 k\x1d*S_\xf1`\x17' b'\xae\twl\x94/\x82\x03\x07E\xaf\xa0\xc1\x8e\xed\xfbv\xf6\xf6\xc8' b'\xba\x8aW\xdb') assert key.verify_tx(data, signature)
def test_xrp_public_key_signature(): private_key = RippleKey() key = RippleKey(public_key=private_key.to_public()) data = {'Account': key.to_account()} with pytest.raises(AssertionError): key.sign_tx(data)
async def sign_and_submit(self, tx: dict, key: RippleKey) -> dict: """ Signs, serializes and submits the transaction using provided key """ tx = deepcopy(tx) if 'SigningPubKey' not in tx: tx['SigningPubKey'] = key.to_public() if 'Sequence' not in tx: info = await self.account_info(tx['Account'], ledger_index='current') tx['Sequence'] = info['account_data']['Sequence'] tx['TxnSignature'] = key.sign_tx(tx) tx_blob = binascii.hexlify(serializer.serialize(tx)).decode() return await self.submit(tx_blob)
async def xrp_transfer_execute(order): """ using ulamlabs/aioxrpy given a simplified order dict with keys: [from, to, quantity] serialize and sign client side locally broadcast the xrp transfer to the ripple public api server """ master = RippleKey(private_key=order["private"]) rpc = RippleJsonRpc(URL) # reserve = await rpc.get_reserve() fee = await rpc.fee() trx = { "Account": master.to_account(), "Flags": RippleTransactionFlags.FullyCanonicalSig, "TransactionType": RippleTransactionType.Payment, "Amount": int(order["quantity"] * 10 ** 6), # conversion to ripple "drops" "Destination": order["to"], "Fee": fee.minimum, } return await rpc.sign_and_submit(trx, master)
async def test_tx_flow_single_sign(master): """ Tests transaction serialization, signing and submitting flow """ rpc = RippleJsonRpc('http://localhost:5005') fee = await rpc.fee() reserve = await rpc.get_reserve() destination = RippleKey() account_info = await rpc.account_info(master.to_account(), ledger_index='current') tx = { 'Account': master.to_account(), 'Flags': RippleTransactionFlags.FullyCanonicalSig, 'Sequence': account_info['account_data']['Sequence'], 'TransactionType': RippleTransactionType.Payment, 'Amount': decimals.xrp_to_drops(reserve.base), 'Destination': destination.to_account(), 'Fee': int(fee.minimum), # as drops 'SigningPubKey': master.to_public() } # sign and serialize transaction signature = master.sign_tx(tx) signed_tx = {**tx, 'TxnSignature': signature} tx_blob = binascii.hexlify(serializer.serialize(signed_tx)).decode() # deserialize and verify signatures deserialized_tx = serializer.deserialize(tx_blob) public_key = RippleKey(public_key=deserialized_tx['SigningPubKey']) assert deserialized_tx == signed_tx assert public_key.verify_tx(tx, signature) # post TX blob to rippled JSONRPC result = await rpc.submit(tx_blob) assert result['engine_result'] == 'tesSUCCESS'
async def test_tx_flow_multi_sign(master): """ Tests transaction serialization, signing and submitting flow with multiple keys """ rpc = RippleJsonRpc('http://localhost:5005') reserve = await rpc.get_reserve() fee = await rpc.fee() account = RippleKey() await rpc.sign_and_submit( { 'Account': master.to_account(), 'Amount': decimals.xrp_to_drops((reserve.base * 2) + 100), 'Flags': RippleTransactionFlags.FullyCanonicalSig, 'TransactionType': RippleTransactionType.Payment, 'Destination': account.to_account(), 'Fee': fee.minimum }, master) # Enable multi-signing account_key_1 = RippleKey() account_key_2 = RippleKey() await rpc.sign_and_submit( { 'Account': account.to_account(), "Flags": RippleTransactionFlags.FullyCanonicalSig, "TransactionType": RippleTransactionType.SignerListSet, "SignerQuorum": 2, "SignerEntries": [{ "SignerEntry": { "Account": account_key_1.to_account(), "SignerWeight": 1 } }, { "SignerEntry": { "Account": account_key_2.to_account(), "SignerWeight": 1 } }], 'Fee': fee.minimum }, account) destination = RippleKey() result = await rpc.multisign_and_submit( { 'Account': account.to_account(), 'Flags': RippleTransactionFlags.FullyCanonicalSig, 'TransactionType': RippleTransactionType.Payment, 'Amount': decimals.xrp_to_drops(reserve.base), 'Destination': destination.to_account(), # Each signature increases transaction cost 'Fee': fee.minimum * 3 }, [account_key_1, account_key_2]) assert result['engine_result'] == 'tesSUCCESS'
def master(): # Master account from genesis ledger # https://xrpl.org/start-a-new-genesis-ledger-in-stand-alone-mode.html return RippleKey(private_key='snoPBrXtMeMyMHUVTgbuqAfg1SUTb')
def test_xrp_key_to_account(): key = RippleKey(private_key='shHM53KPZ87Gwdqarm1bAmPeXg8Tn') assert key.to_account() == 'rhcfR9Cg98qCxHpCcPBmMonbDBXo84wyTn'
def test_xrp_key_to_public(): key = RippleKey(private_key='shHM53KPZ87Gwdqarm1bAmPeXg8Tn') assert key.to_public() == ( b'\x03\xfa%\xb6\x8d\xa6\xffh2\xe4F/\xdf\xb9\xa2\xaa\xa5\x88\x88\xc0' b'\xed\x17(_\xfe\x92\xe4F^\x0cnx*')
def test_xrp_key_creating(): key1 = RippleKey() key2 = RippleKey() assert key1._sk.to_string() != key2._sk.to_string()
def test_xrp_key_from_hex(): hex_key = binascii.unhexlify( '42aa52b7da6fc94b8ee8946aeccafb6a03b1f62de2095834e3dcf26d55e0d458') key = RippleKey(private_key=hex_key) assert key._sk.to_string() == hex_key