Skip to content

Commit 2a1a5c8

Browse files
fishronsage流戈
authored andcommitted
basic implementation of fungible asset client
1 parent e5e1ecb commit 2a1a5c8

File tree

2 files changed

+507
-1
lines changed

2 files changed

+507
-1
lines changed

aptos_sdk/aptos_token_client.py

Lines changed: 260 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from __future__ import annotations
55

6-
from typing import Any, List, Tuple
6+
from typing import Any, List, Optional, Tuple
77

88
from .account import Account
99
from .account_address import AccountAddress
@@ -298,13 +298,53 @@ def parse(resource: dict[str, Any]) -> PropertyMap:
298298
return PropertyMap(properties)
299299

300300

301+
class FAConcurrentSupply:
302+
value: int
303+
max_value: int
304+
305+
struct_tag = "0x1::fungible_asset::ConcurrentSupply"
306+
307+
def __init__(self, value: int, max_value: int) -> None:
308+
self.value = value
309+
self.max_value = max_value
310+
311+
def __str__(self) -> str:
312+
return f"FAConcurrentSupply[value: {self.value}, max_value: {self.max_value}]"
313+
314+
@staticmethod
315+
def parse(resource: dict[str, Any]) -> FAConcurrentSupply:
316+
return FAConcurrentSupply(
317+
int(resource["current"]["value"]), int(resource["current"]["max_value"])
318+
)
319+
320+
321+
class FungibleStore:
322+
balance: int
323+
frozen: bool
324+
325+
struct_tag = "0x1::fungible_asset::FungibleStore"
326+
327+
def __init__(self, balance: int, frozen: bool) -> None:
328+
self.balance = balance
329+
self.frozen = frozen
330+
331+
def __str__(self):
332+
return f"FungibleStore[balance: {self.balance}, frozen: {self.frozen}]"
333+
334+
@staticmethod
335+
def parse(resource: dict[str, Any]) -> FungibleStore:
336+
return FungibleStore(int(resource["balance"]), resource["frozen"])
337+
338+
301339
class ReadObject:
302340
resource_map: dict[str, Any] = {
303341
Collection.struct_tag: Collection,
304342
Object.struct_tag: Object,
305343
PropertyMap.struct_tag: PropertyMap,
306344
Royalty.struct_tag: Royalty,
307345
Token.struct_tag: Token,
346+
FAConcurrentSupply.struct_tag: FAConcurrentSupply,
347+
FungibleStore.struct_tag: FungibleStore,
308348
}
309349

310350
resources: dict[Any, Any]
@@ -631,3 +671,222 @@ async def tokens_minted_from_transaction(
631671
continue
632672
mints.append(AccountAddress.from_str_relaxed(event["data"]["token"]))
633673
return mints
674+
675+
676+
class FungibleAssetClient:
677+
"""A wrapper around reading and mutating Fungible Assets"""
678+
679+
def __init__(self, rest_client: RestClient):
680+
self.client = rest_client
681+
682+
async def __primary_store_view(
683+
self,
684+
function: str,
685+
args: List[TransactionArgument],
686+
ledger_version: Optional[int] = None,
687+
) -> Any:
688+
module = "0x1::primary_fungible_store"
689+
ty_args = [TypeTag(StructTag.from_str("0x1::fungible_asset::Metadata"))]
690+
return await self.client.view_bcs_payload(
691+
module, function, ty_args, args, ledger_version
692+
)
693+
694+
async def __metadata_view(
695+
self,
696+
function: str,
697+
args: List[TransactionArgument],
698+
ledger_version: Optional[int] = None,
699+
) -> Any:
700+
module = "0x1::fungible_asset"
701+
ty_args = [TypeTag(StructTag.from_str("0x1::fungible_asset::Metadata"))]
702+
return await self.client.view_bcs_payload(
703+
module, function, ty_args, args, ledger_version
704+
)
705+
706+
async def read_object(self, address: AccountAddress) -> ReadObject:
707+
resources = {}
708+
read_resources = await self.client.account_resources(address)
709+
for resource in read_resources:
710+
if resource["type"] in ReadObject.resource_map:
711+
resource_obj = ReadObject.resource_map[resource["type"]]
712+
resources[resource_obj] = resource_obj.parse(resource["data"])
713+
return ReadObject(resources)
714+
715+
async def supply(
716+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
717+
) -> int:
718+
"""Get the current supply from the metadata object."""
719+
resp = await self.__metadata_view(
720+
"supply",
721+
[
722+
TransactionArgument(metadata_address, Serializer.struct),
723+
],
724+
ledger_version,
725+
)
726+
return int(resp[0]["vec"][0])
727+
728+
async def maximum(
729+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
730+
) -> int:
731+
"""Get the maximum supply from the metadata object. If supply is unlimited (or set explicitly to MAX_U128), none is returned."""
732+
resp = await self.__metadata_view(
733+
"maximum",
734+
[
735+
TransactionArgument(metadata_address, Serializer.struct),
736+
],
737+
ledger_version,
738+
)
739+
return int(resp[0]["vec"][0])
740+
741+
async def name(
742+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
743+
) -> str:
744+
"""Get the name of the fungible asset from the metadata object."""
745+
resp = await self.__metadata_view(
746+
"name",
747+
[
748+
TransactionArgument(metadata_address, Serializer.struct),
749+
],
750+
ledger_version,
751+
)
752+
return resp[0]
753+
754+
async def symbol(
755+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
756+
) -> str:
757+
"""Get the symbol of the fungible asset from the metadata object."""
758+
resp = await self.__metadata_view(
759+
"symbol",
760+
[
761+
TransactionArgument(metadata_address, Serializer.struct),
762+
],
763+
ledger_version,
764+
)
765+
return resp[0]
766+
767+
async def decimals(
768+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
769+
) -> int:
770+
"""Get the decimals from the metadata object."""
771+
resp = await self.__metadata_view(
772+
"decimals",
773+
[
774+
TransactionArgument(metadata_address, Serializer.struct),
775+
],
776+
ledger_version,
777+
)
778+
return int(resp[0])
779+
780+
async def icon_uri(
781+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
782+
) -> str:
783+
"""Get the icon uri from the metadata object."""
784+
resp = await self.__metadata_view(
785+
"icon_uri",
786+
[
787+
TransactionArgument(metadata_address, Serializer.struct),
788+
],
789+
ledger_version,
790+
)
791+
return resp[0]
792+
793+
async def project_uri(
794+
self, metadata_address: AccountAddress, ledger_version: Optional[int] = None
795+
) -> str:
796+
"""Get the project uri from the metadata object."""
797+
resp = await self.__metadata_view(
798+
"project_uri",
799+
[
800+
TransactionArgument(metadata_address, Serializer.struct),
801+
],
802+
ledger_version,
803+
)
804+
return resp[0]
805+
806+
async def store_metadata(
807+
self, address: AccountAddress, ledger_version: Optional[int] = None
808+
) -> str:
809+
"""Return the underlying metadata object."""
810+
resp = await self.client.view_bcs_payload(
811+
"0x1::fungible_asset",
812+
"store_metadata",
813+
[TypeTag(StructTag.from_str("0x1::fungible_asset::FungibleStore"))],
814+
[TransactionArgument(address, Serializer.struct)],
815+
ledger_version,
816+
)
817+
return resp[0]
818+
819+
async def transfer(
820+
self,
821+
sender: Account,
822+
metadata_address: AccountAddress,
823+
receiver_address: AccountAddress,
824+
amount: int,
825+
sequence_number: Optional[int] = None,
826+
) -> str:
827+
"""Transfer amount of fungible asset from sender's primary store to receiver's primary store."""
828+
payload = EntryFunction.natural(
829+
"0x1::primary_fungible_store",
830+
"transfer",
831+
[TypeTag(StructTag.from_str("0x1::fungible_asset::Metadata"))],
832+
[
833+
TransactionArgument(metadata_address, Serializer.struct),
834+
TransactionArgument(receiver_address, Serializer.struct),
835+
TransactionArgument(amount, Serializer.u64),
836+
],
837+
)
838+
signed_transaction = await self.client.create_bcs_signed_transaction(
839+
sender, TransactionPayload(payload), sequence_number=sequence_number
840+
)
841+
return await self.client.submit_bcs_transaction(signed_transaction)
842+
843+
async def balance(
844+
self,
845+
metadata_address: AccountAddress,
846+
address: AccountAddress,
847+
ledger_version: Optional[int] = None,
848+
) -> int:
849+
"""Get the balance of account's primary store."""
850+
resp = await self.__primary_store_view(
851+
"balance",
852+
[
853+
TransactionArgument(address, Serializer.struct),
854+
TransactionArgument(metadata_address, Serializer.struct),
855+
],
856+
ledger_version,
857+
)
858+
return int(resp[0])
859+
860+
async def is_frozen(
861+
self,
862+
metadata_address: AccountAddress,
863+
address: AccountAddress,
864+
ledger_version: Optional[int] = None,
865+
) -> bool:
866+
"""Return whether the given account's primary store is frozen."""
867+
resp = await self.__primary_store_view(
868+
"is_frozen",
869+
[
870+
TransactionArgument(address, Serializer.struct),
871+
TransactionArgument(metadata_address, Serializer.struct),
872+
],
873+
ledger_version,
874+
)
875+
return resp[0]
876+
877+
async def primary_store_address(
878+
self,
879+
metadata_address,
880+
address: AccountAddress,
881+
ledger_version: Optional[int] = None,
882+
) -> str:
883+
"""Get the address of the primary store for the given account."""
884+
resp = await self.__primary_store_view(
885+
"primary_store_address",
886+
[
887+
TransactionArgument(address, Serializer.struct),
888+
TransactionArgument(metadata_address, Serializer.struct),
889+
],
890+
ledger_version,
891+
)
892+
return resp[0]

0 commit comments

Comments
 (0)