Skip to content

Commit

Permalink
feat: Add Asset.contract_id() for calculating the id of the asset c…
Browse files Browse the repository at this point in the history
…ontract. (#901)
  • Loading branch information
overcat committed Mar 12, 2024
1 parent 20477c0 commit 43b9a58
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Release History
### Pending
#### Update
- chore: throw an exception when the API does not provide streaming support. ([#878](https://github.com/StellarCN/py-stellar-base/pull/878))
- feat: Add `Asset.contract_id()` for calculating the id of the asset contract. ([#901](https://github.com/StellarCN/py-stellar-base/pull/901))

### Version 9.2.0

Expand Down
22 changes: 22 additions & 0 deletions stellar_sdk/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from . import xdr as stellar_xdr
from .exceptions import AssetCodeInvalidError, AssetIssuerInvalidError
from .keypair import Keypair
from .network import Network
from .strkey import StrKey
from .utils import sha256

__all__ = ["Asset"]

Expand Down Expand Up @@ -82,6 +84,26 @@ def type(self) -> str:
def type(self, v) -> None:
raise AttributeError("Asset type is immutable.")

def contract_id(self, network_passphrase: str) -> str:
"""Return the contract Id for the asset contract.
:param network_passphrase: The network where the asset is located.
:return: The contract Id for the asset contract.
"""
network_id_hash = stellar_xdr.Hash(Network(network_passphrase).network_id())
preimage = stellar_xdr.HashIDPreimage(
stellar_xdr.EnvelopeType.ENVELOPE_TYPE_CONTRACT_ID,
contract_id=stellar_xdr.HashIDPreimageContractID(
network_id=network_id_hash,
contract_id_preimage=stellar_xdr.ContractIDPreimage(
stellar_xdr.ContractIDPreimageType.CONTRACT_ID_PREIMAGE_FROM_ASSET,
from_asset=self.to_xdr_object(),
),
),
)
contract_id = sha256(preimage.to_xdr_bytes())
return StrKey.encode_contract(contract_id)

def guess_asset_type(self) -> str:
"""Return the type of the asset, Can be one of
following types: ``native``, ``credit_alphanum4`` or ``credit_alphanum12``.
Expand Down
9 changes: 6 additions & 3 deletions stellar_sdk/utils.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
"""This file contains constants, functions and classes used internally by this SDK.
They may change at any time, so please do not use them directly.
"""

import hashlib
import re
from decimal import ROUND_FLOOR, Context, Decimal, Inexact
from typing import Dict, Optional, Sequence, Union
from typing import TYPE_CHECKING, Dict, Optional, Sequence, Union
from urllib.parse import urljoin, urlsplit, urlunsplit

from .asset import Asset
from .exceptions import Ed25519PublicKeyInvalidError, NoApproximationError
from .strkey import StrKey

if TYPE_CHECKING:
from .asset import Asset

MUXED_ACCOUNT_STARTING_LETTER: str = "M"
ED25519_PUBLIC_KEY_STARTING_LETTER: str = "G"
_LOWER_LIMIT = "0"
Expand Down Expand Up @@ -55,7 +58,7 @@ def hex_to_bytes(hex_string: Union[str, bytes]) -> bytes:
return hex_string


def convert_assets_to_horizon_param(assets: Sequence[Asset]) -> str:
def convert_assets_to_horizon_param(assets: Sequence["Asset"]) -> str:
assets_string = []
for asset in assets:
if asset.is_native():
Expand Down
37 changes: 37 additions & 0 deletions tests/test_asset.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest

from stellar_sdk import Network
from stellar_sdk.asset import Asset
from stellar_sdk.exceptions import AssetCodeInvalidError, AssetIssuerInvalidError

Expand Down Expand Up @@ -180,3 +181,39 @@ def test_to_xdr_change_trust_xdr_asset_object(self, asset, xdr):
xdr_object = asset.to_change_trust_asset_xdr_object()
assert xdr_object.to_xdr() == xdr
assert Asset.from_xdr_object(xdr_object) == asset

@pytest.mark.parametrize(
"asset, network_passphrase, contract_id",
[
pytest.param(
Asset.native(),
Network.PUBLIC_NETWORK_PASSPHRASE,
"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA",
id="native_public",
),
pytest.param(
Asset.native(),
Network.TESTNET_NETWORK_PASSPHRASE,
"CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
id="native_testnet",
),
pytest.param(
Asset(
"USDC", "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
),
Network.PUBLIC_NETWORK_PASSPHRASE,
"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
id="alphanum4_public",
),
pytest.param(
Asset(
"yUSDC", "GDGTVWSM4MGS4T7Z6W4RPWOCHE2I6RDFCIFZGS3DOA63LWQTRNZNTTFF"
),
Network.PUBLIC_NETWORK_PASSPHRASE,
"CDOFW7HNKLUZRLFZST4EW7V3AV4JI5IHMT6BPXXSY2IEFZ4NE5TWU2P4",
id="alphanum12_public",
),
],
)
def test_contract_id(self, asset, network_passphrase, contract_id):
assert asset.contract_id(network_passphrase) == contract_id

0 comments on commit 43b9a58

Please sign in to comment.