def from_value(cls: Type[Amount], value: Union[str, Dict[str, str]]) -> Amount: """ Construct an Amount from an issued currency amount or (for XRP), a string amount. See `Amount Fields <https://xrpl.org/serialization.html#amount-fields>`_ Args: value: The value from which to construct an Amount. Returns: An Amount object. Raises: XRPLBinaryCodecException: if an Amount cannot be constructed. """ if isinstance(value, str): return cls(_serialize_xrp_amount(value)) if IssuedCurrencyAmount.is_dict_of_model(value): return cls(_serialize_issued_currency_amount(value)) raise XRPLBinaryCodecException( "Invalid type to construct an Amount: expected str or dict," f" received {value.__class__.__name__}.")
def _from_dict_special_cases( cls: Type[BaseModel], param: str, param_type: Type[Any], param_value: Dict[str, Any], ) -> Union[str, Enum, BaseModel, Dict[str, Any]]: """Handles all the recursive/more complex cases for `from_dict`.""" from xrpl.models.amounts import Amount, IssuedCurrencyAmount from xrpl.models.currencies import XRP, Currency, IssuedCurrency from xrpl.models.transactions.transaction import Transaction # TODO: figure out how to make Unions work generically (if possible) if param_type == Amount: # special case, Union if isinstance(param_value, str): return param_value if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") return IssuedCurrencyAmount.from_dict(param_value) if param_type == Currency: # special case, Union if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") if "currency" in param_value and "issuer" in param_value: return IssuedCurrency.from_dict(param_value) if "currency" in param_value: param_value_copy = {**param_value} del param_value_copy["currency"] return XRP.from_dict(param_value_copy) raise XRPLModelException(f"No valid type for {param}") if param_type == Transaction: # special case, multiple options (could be any Transaction type) if "transaction_type" not in param_value: raise XRPLModelException( f"{param} not a valid parameter for {cls.__name__}") type_str = param_value["transaction_type"] # safely convert type string into the actual type transaction_type = Transaction.get_transaction_type(type_str) param_value_copy = {**param_value} del param_value_copy["transaction_type"] return transaction_type.from_dict(param_value_copy) if param_type in BaseModel.__subclasses__(): # any other BaseModel if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") # mypy doesn't know that the If checks that it's a subclass of BaseModel return param_type.from_dict(param_value) # type: ignore if param_type in Enum.__subclasses__(): # mypy doesn't know that the If checks that it's a subclass of Enum return param_type(param_value) # type: ignore return param_value
async def _set_up_reusable_values(): WALLET = await generate_faucet_wallet(ASYNC_JSON_RPC_CLIENT) DESTINATION = await generate_faucet_wallet(ASYNC_JSON_RPC_CLIENT) OFFER = await sign_and_reliable_submission_async( OfferCreate( account=WALLET.classic_address, sequence=WALLET.sequence, taker_gets="13100000", taker_pays=IssuedCurrencyAmount( currency="USD", issuer=WALLET.classic_address, value="10", ), ), WALLET, ) WALLET.sequence += 1 PAYMENT_CHANNEL = await sign_and_reliable_submission_async( PaymentChannelCreate( account=WALLET.classic_address, sequence=WALLET.sequence, amount="1", destination=DESTINATION.classic_address, settle_delay=86400, public_key=WALLET.public_key, ), WALLET, ) WALLET.sequence += 1 return WALLET, DESTINATION, OFFER, PAYMENT_CHANNEL
def _value_to_tx_json(value: Any) -> Any: # IssuedCurrencyAmount is a special case and should not be snake cased if IssuedCurrencyAmount.is_dict_of_model(value): return {key: _value_to_tx_json(sub_value) for (key, sub_value) in value.items()} if isinstance(value, dict): return transaction_json_to_binary_codec_form(value) if isinstance(value, list): return [_value_to_tx_json(sub_value) for sub_value in value] return value
def _value_to_tx_json(value: Any) -> Any: # IssuedCurrencyAmount and PathStep are special cases and should not be snake cased # and only contain primitive members if IssuedCurrencyAmount.is_dict_of_model( value) or PathStep.is_dict_of_model(value): return value if isinstance(value, dict): return transaction_json_to_binary_codec_form(value) if isinstance(value, list): return [_value_to_tx_json(sub_value) for sub_value in value] return value
async def test_basic_functionality(self, client): offer = await submit_transaction_async( OfferCreate( account=WALLET.classic_address, sequence=WALLET.sequence, taker_gets="13100000", taker_pays=IssuedCurrencyAmount( currency="USD", issuer=WALLET.classic_address, value="10", ), ), WALLET, ) self.assertTrue(offer.is_successful()) WALLET.sequence += 1
async def test_basic_functionality(self, client): issuer_wallet = Wallet.create() response = await submit_transaction_async( TrustSet( account=WALLET.classic_address, sequence=WALLET.sequence, flags=TrustSetFlag.TF_SET_NO_RIPPLE, limit_amount=IssuedCurrencyAmount( issuer=issuer_wallet.classic_address, currency="USD", value="100", ), ), WALLET, ) self.assertTrue(response.is_successful()) WALLET.sequence += 1
def test_basic_functionality(self): issuer_wallet = Wallet.create() response = submit_transaction( TrustSet( account=WALLET.classic_address, sequence=WALLET.next_sequence_num, fee=FEE, flags=TrustSetFlag.TF_SET_NO_RIPPLE, limit_amount=IssuedCurrencyAmount( issuer=issuer_wallet.classic_address, currency="USD", value="100", ), ), WALLET, ) self.assertTrue(response.is_successful())
def test_from_dict_explicit_none(self): dictionary = { "account": "rH6ZiHU1PGamME2LvVTxrgvfjQpppWKGmr", "fee": "10", "sequence": None, "flags": TrustSetFlag.TF_SET_NO_RIPPLE, "limit_amount": { "currency": "USD", "issuer": "raoV5dkC66XvGWjSzUhCUuuGM3YFTitMxT", "value": "100", }, } expected = TrustSet( account="rH6ZiHU1PGamME2LvVTxrgvfjQpppWKGmr", fee="10", flags=TrustSetFlag.TF_SET_NO_RIPPLE.value, limit_amount=IssuedCurrencyAmount( currency="USD", issuer="raoV5dkC66XvGWjSzUhCUuuGM3YFTitMxT", value="100"), ) actual = TrustSet.from_dict(dictionary) self.assertEqual(actual, expected)
def test_from_xrpl_memos(self): memo_type = "687474703a2f2f6578616d706c652e636f6d2f6d656d6f2f67656e65726963" tx = { "Account": "rnoGkgSpt6AX1nQxZ2qVGx7Fgw6JEcoQas", "TransactionType": "TrustSet", "Fee": "10", "Sequence": 17892983, "Flags": 131072, "Memos": [{ "Memo": { "MemoType": memo_type, "MemoData": "72656e74", } }], "SigningPubKey": "", "LimitAmount": { "currency": "USD", "issuer": "rBPvTKisx7UCGLDtiUZ6mDssXNREuVuL8Y", "value": "10", }, } expected = TrustSet( account="rnoGkgSpt6AX1nQxZ2qVGx7Fgw6JEcoQas", fee="10", sequence=17892983, flags=131072, memos=[Memo( memo_type=memo_type, memo_data="72656e74", )], limit_amount=IssuedCurrencyAmount( currency="USD", issuer="rBPvTKisx7UCGLDtiUZ6mDssXNREuVuL8Y", value="10"), ) self.assertEqual(Transaction.from_xrpl(tx), expected)
def test_from_dict_trust_set(self): dictionary = { "account": "rH6ZiHU1PGamME2LvVTxrgvfjQpppWKGmr", "fee": "10", "sequence": 16178313, "flags": 131072, "limit_amount": { "currency": "USD", "issuer": "raoV5dkC66XvGWjSzUhCUuuGM3YFTitMxT", "value": "100", }, } expected = TrustSet( account="rH6ZiHU1PGamME2LvVTxrgvfjQpppWKGmr", fee="10", sequence=16178313, flags=131072, limit_amount=IssuedCurrencyAmount( currency="USD", issuer="raoV5dkC66XvGWjSzUhCUuuGM3YFTitMxT", value="100"), ) actual = TrustSet.from_dict(dictionary) self.assertEqual(actual, expected)
from tests.integration.it_utils import JSON_RPC_CLIENT, sign_and_reliable_submission from xrpl.models.amounts import IssuedCurrencyAmount from xrpl.models.transactions import OfferCreate, PaymentChannelCreate from xrpl.wallet import generate_faucet_wallet WALLET = generate_faucet_wallet(JSON_RPC_CLIENT) DESTINATION = generate_faucet_wallet(JSON_RPC_CLIENT) OFFER = sign_and_reliable_submission( OfferCreate( account=WALLET.classic_address, sequence=WALLET.sequence, taker_gets="13100000", taker_pays=IssuedCurrencyAmount( currency="USD", issuer=WALLET.classic_address, value="10", ), ), WALLET, ) WALLET.sequence += 1 PAYMENT_CHANNEL = sign_and_reliable_submission( PaymentChannelCreate( account=WALLET.classic_address, sequence=WALLET.sequence, amount="1", destination=DESTINATION.classic_address, settle_delay=86400, public_key=WALLET.public_key,
def test_from_dict_basic(self): amount = IssuedCurrencyAmount.from_dict(amount_dict) self.assertEqual(amount, IssuedCurrencyAmount(**amount_dict))
def test_is_dict_of_model_when_not_true(self): self.assertFalse( Sign.is_dict_of_model( IssuedCurrencyAmount.from_dict(amount_dict).to_dict(), ), )
def test_repr(self): amount = IssuedCurrencyAmount(**amount_dict) expected_repr = (f"IssuedCurrencyAmount(currency='{currency}', " f"issuer='{issuer}', value='{value}')") self.assertEqual(repr(amount), expected_repr)
def test_eq(self): amount = IssuedCurrencyAmount(**amount_dict) self.assertEqual(amount, IssuedCurrencyAmount(**amount_dict))
def test_to_xrpl_paths(self): paths_json = [ [ { "account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B", "type": 1 }, { "currency": "USD", "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", "type": 48, }, { "account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", "type": 1 }, { "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "type": 1 }, ], ] p = Payment( account="rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", amount=IssuedCurrencyAmount( currency="USD", issuer="rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", value="0.0001", ), destination="rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", send_max=IssuedCurrencyAmount( currency="BTC", issuer="rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", value="0.0000002831214446", ), paths=paths_json, sequence=290, ) tx_json = p.to_xrpl() expected = { "Account": "rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", "TransactionType": "Payment", "Sequence": 290, "Flags": 0, "SigningPubKey": "", "Amount": { "currency": "USD", "issuer": "rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", "value": "0.0001", }, "Destination": "rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", "Paths": [[ { "account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B", "type": 1 }, { "currency": "USD", "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", "type": 48, }, { "account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", "type": 1 }, { "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "type": 1 }, ]], "SendMax": { "currency": "BTC", "issuer": "rweYz56rfmQ98cAdRaeTxQS9wVMGnrdsFp", "value": "0.0000002831214446", }, } self.assertEqual(tx_json, expected)
def test_from_xrpl_signers(self): txn_sig1 = ( "F80E201FE295AA08678F8542D8FC18EA18D582A0BD19BE77B9A24479418ADBCF4CAD28E7BD" "96137F88DE7736827C7AC6204FBA8DDADB7394E6D704CD1F4CD609") txn_sig2 = ( "036E95B8100EBA2A4A447A3AF24500261BF480A0E8D62EE15D03A697C85E73237A5202BD9A" "F2D9C68B8E8A5FA8B8DA4F8DABABE95E8401C5E57EC783291EF80C") pubkey1 = "ED621D6D4FF54E809397195C4E24EF05E8500A7CE45CDD211F523A892CDBCDCDB2" pubkey2 = "EDD3ABCFF008ECE9ED3073B41913619341519BFF01F07331B56E5D6D2EC4A94A57" tx = { "Account": "rnoGkgSpt6AX1nQxZ2qVGx7Fgw6JEcoQas", "TransactionType": "TrustSet", "Fee": "10", "Sequence": 17892983, "Flags": 131072, "Signers": [ { "Signer": { "Account": "rGVXgBz4NraZcwi5vqpmwPW6P4y74A4YvX", "TxnSignature": txn_sig1, "SigningPubKey": pubkey1, } }, { "Signer": { "Account": "rB5q2wsHeXdQeh2KFzBb1CujNAfSKys6GN", "TxnSignature": txn_sig2, "SigningPubKey": pubkey2, } }, ], "SigningPubKey": "", "LimitAmount": { "currency": "USD", "issuer": "rBPvTKisx7UCGLDtiUZ6mDssXNREuVuL8Y", "value": "10", }, } expected = TrustSet( account="rnoGkgSpt6AX1nQxZ2qVGx7Fgw6JEcoQas", fee="10", sequence=17892983, flags=131072, signers=[ Signer( account="rGVXgBz4NraZcwi5vqpmwPW6P4y74A4YvX", txn_signature=txn_sig1, signing_pub_key=pubkey1, ), Signer( account="rB5q2wsHeXdQeh2KFzBb1CujNAfSKys6GN", txn_signature=txn_sig2, signing_pub_key=pubkey2, ), ], limit_amount=IssuedCurrencyAmount( currency="USD", issuer="rBPvTKisx7UCGLDtiUZ6mDssXNREuVuL8Y", value="10"), ) self.assertEqual(Transaction.from_xrpl(tx), expected)
def test_from_dict_multisign(self): txn_sig1 = ( "F80E201FE295AA08678F8542D8FC18EA18D582A0BD19BE77B9A24479418ADBCF4CAD28E7BD" "96137F88DE7736827C7AC6204FBA8DDADB7394E6D704CD1F4CD609") txn_sig2 = ( "036E95B8100EBA2A4A447A3AF24500261BF480A0E8D62EE15D03A697C85E73237A5202BD9A" "F2D9C68B8E8A5FA8B8DA4F8DABABE95E8401C5E57EC783291EF80C") pubkey1 = "ED621D6D4FF54E809397195C4E24EF05E8500A7CE45CDD211F523A892CDBCDCDB2" pubkey2 = "EDD3ABCFF008ECE9ED3073B41913619341519BFF01F07331B56E5D6D2EC4A94A57" request = { "method": "submit_multisigned", "tx_json": { "Account": "rnD6t3JF9RTG4VgNLoc4i44bsQLgJUSi6h", "TransactionType": "TrustSet", "Fee": "10", "Sequence": 17896798, "Flags": 131072, "Signers": [ { "Signer": { "Account": "rGoKUCwJ2C4oHUsqnd8PVxZhFiBMV2T42G", "TxnSignature": txn_sig1, "SigningPubKey": pubkey1, } }, { "Signer": { "Account": "rsi3GL27pstEYUJ28ZM3q155rmFCCTBCZ1", "TxnSignature": txn_sig2, "SigningPubKey": pubkey2, } }, ], "SigningPubKey": "", "LimitAmount": { "currency": "USD", "issuer": "rH5gvkKxGHrFAMAACeu9CB3FMu7pQ9jfZm", "value": "10", }, }, "fail_hard": False, } expected = SubmitMultisigned(tx_json=TrustSet( account="rnD6t3JF9RTG4VgNLoc4i44bsQLgJUSi6h", fee="10", sequence=17896798, flags=131072, signers=[ Signer( account="rGoKUCwJ2C4oHUsqnd8PVxZhFiBMV2T42G", txn_signature=txn_sig1, signing_pub_key=pubkey1, ), Signer( account="rsi3GL27pstEYUJ28ZM3q155rmFCCTBCZ1", txn_signature=txn_sig2, signing_pub_key=pubkey2, ), ], limit_amount=IssuedCurrencyAmount( currency="USD", issuer="rH5gvkKxGHrFAMAACeu9CB3FMu7pQ9jfZm", value="10", ), ), ) actual = Request.from_dict(request) self.assertEqual(actual, expected)
def test_basic_functionality(self): # # Perform multisign # # NOTE: If you need to use xrpl-py for multisigning, please create an issue on # the repo. We'd like to gauge interest in higher level multisigning # functionality. issuer = Wallet.create() tx = TrustSet( account=WALLET.classic_address, sequence=WALLET.next_sequence_num, fee=FEE, flags=TrustSetFlag.TF_SET_NO_RIPPLE, limit_amount=IssuedCurrencyAmount( issuer=issuer.classic_address, currency="USD", value="10", ), ) tx_json = transaction_json_to_binary_codec_form(tx.to_dict()) first_sig = sign( bytes.fromhex( encode_for_multisigning( tx_json, FIRST_SIGNER.classic_address, )), FIRST_SIGNER.private_key, ) second_sig = sign( bytes.fromhex( encode_for_multisigning( tx_json, SECOND_SIGNER.classic_address, )), SECOND_SIGNER.private_key, ) multisigned_tx = TrustSet( account=WALLET.classic_address, sequence=WALLET.next_sequence_num, fee=FEE, flags=TrustSetFlag.TF_SET_NO_RIPPLE, limit_amount=IssuedCurrencyAmount( issuer=issuer.classic_address, currency="USD", value="10", ), signers=[ Signer( account=FIRST_SIGNER.classic_address, txn_signature=first_sig, signing_pub_key=FIRST_SIGNER.public_key, ), Signer( account=SECOND_SIGNER.classic_address, txn_signature=second_sig, signing_pub_key=SECOND_SIGNER.public_key, ), ], ) # submit tx response = JSON_RPC_CLIENT.request( SubmitMultisigned(tx_json=transaction_json_to_binary_codec_form( multisigned_tx.to_dict()), )) self.assertTrue(response.is_successful())