{"id":13524768,"url":"https://github.com/Toniq-Labs/extendable-token","last_synced_at":"2025-04-01T03:32:35.753Z","repository":{"id":38848107,"uuid":"375907875","full_name":"Toniq-Labs/extendable-token","owner":"Toniq-Labs","description":null,"archived":false,"fork":false,"pushed_at":"2023-03-23T14:37:15.000Z","size":113,"stargazers_count":88,"open_issues_count":16,"forks_count":47,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-08-02T06:17:07.484Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Motoko","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Toniq-Labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-06-11T04:50:22.000Z","updated_at":"2024-04-10T10:11:58.000Z","dependencies_parsed_at":"2024-01-25T10:33:48.283Z","dependency_job_id":"0f178f8d-a4a9-494f-b6f2-985df3f14b96","html_url":"https://github.com/Toniq-Labs/extendable-token","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toniq-Labs%2Fextendable-token","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toniq-Labs%2Fextendable-token/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toniq-Labs%2Fextendable-token/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toniq-Labs%2Fextendable-token/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Toniq-Labs","download_url":"https://codeload.github.com/Toniq-Labs/extendable-token/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222698187,"owners_count":17024877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:13.276Z","updated_at":"2024-11-02T09:30:27.415Z","avatar_url":"https://github.com/Toniq-Labs.png","language":"Motoko","funding_links":[],"categories":["Fungible and Non-fungible Tokens (NFTs)","Lib","Applications"],"sub_categories":["Interface Standards","Cryptocurrencies"],"readme":"# EXT Standard\n## The extendable token standard\n\nThis token standard provides a ERC1155/multi-token-like approach with extensions that can add additional functionality based on the purpose of the token. EXT Standard allows for the following features:\n1. Multiple tokens (which can be a mix, e.g. fungible and non-fungible) within a single canister. This provides better computation/gas savings and can reduce complexities.\n2. Bulit-in transfer notifications for more streamlined usage (e.g. similar to `transferAndCall`).\n3. Supports both native `AccountIdentifier`s (64 long hex strings) and `Principal`s. EXT integrates well with both address styles making it easier for end users to interact with.\n4. Extendable standard with a method to query a token's capabilities to aid in deciding how to communicate with it (better integration with 3rd party tools).\n5. A unique `TokenIdentifier` is generated for each token with a canister (e.g. cnvzt-kikor-uwiaa-aaaaa-b4aah-eaqca-aaaaa-a) which is constructed using the canister ID and the token index within the canister. The canister ID can also be used which would point to the 0 index token (perfect if you have a single token like the [erc20 example](examples/erc20.mo))\n6. WIP: Building a new core entrypoint named `exchange` to incorporate exchange mechanism directly into our core token standard\n\nHere are some of the initial extensions we are working on:\n\n* allowance - ERC20 like allowances\n* archive - Transaction archive\n* batch - Batch transfer/balance functions\n* common - Some common token methods (metadata, supply)\n* fee - A way to provide a standard fee\n* ledger - ICP Ledger-like interface\n* operator - Operator's for spending tokens\n* secure - Add's update calls for common queries (more secure)\n* subscribe - Provide interface for notification subscription\n\nYou can view more details [here](EXTENSIONS.md).\n\n**Please comment, submit PRs, publish your own extensions and collaborate with us to build this standard.**\n\n## Examples\n\nWe have a number of examples that you can use in the `examples` dirextory - all of these work with the EXT interface and can be added to a supporting wallet like Stoic:\n\n* [ERC20](examples/erc20.md) - an ERC20-like standard that is very basic\n* [ERC721](examples/erc721.md) - as per the above, except for NFTs specifically\n* [Standard](examples/standard.md) - our standard single-token implementation with notifications\n* [Advanced](examples/advanced.md) - our advanced multi-token implementation\n\n## Rationale\nTokens can be used in a wide variety of circumstances, from cryptocurrency ledgers to in-game assets and more. These tokens can serve different purposes and therefore need to allow for a wide variety of functionalities. On the other hand, 3rd party tools that need to integrate with tokens would benefit from a standardized interface.\n\nEXT Standard promotes modular development of tokens using extensions and a common core. Token developers can developer their tokens based on their exact use case, and 3rd party developers can build tools around these tokens using the standardized interfaces.\n\nThis repo contains our core standard and a number of initial extensions. We have added a full motoko library of these modules, and have provided some [examples](examples). We are also developing a basic JS library to easily integrate EXT with your applications.\n\n## Interface Specification\nThe ext-core standard requires the following public entry points:\n\n```\ntype Token = actor {\n  extensions : shared query () -\u003e async [Extension];\n    \n  balance: shared query (request : BalanceRequest) -\u003e async BalanceResponse;\n      \n  transfer: shared (request : TransferRequest) -\u003e async TransferResponse;\n};\n```\n\n## Types\n### Native ICP Ledger types\n```\ntype AccountIdentifier = Text;\ntype SubAccount = [Nat8];\n```\nBasic support for ICP Ledger `AccountIdentifier`s (64 long hex addresses) and `SubAccount`s (an index for a Principal).\n\n### User\n```\ntype User = {\n  #address : AccountIdentifier;\n  #principal : Principal;\n}\n```\nEXT supports both native `AccountIdentifier`s (64 long hex addresses) and `Principal`s. EXT contains methods to check equality and generate a hash of a User. We advise storing balances against the AccountIdentifier as a Principal can be easily converted to one (using the default 0 index).\n\n### Balance\n```\ntype Balance = Nat;\n```\nBalance refers to an amount of a particular `TokenIdentifier`. For the cases of non-fungible tokens, this would be `0` or `1`.\n\n### TokenIdentifier\n```\n// \\x0Atid\" + canisterId + 32 bit index\ntype TokenIdentifier  = Text;\n```\nThe `TokenIdentifier` is a unique id for a particular token and reflects the canister where the token exists as well as the index within the tokens container. The TokenIdentifier is similar to a `Principal` and is a representation of the canister's ID, the index of the token within the canister, and a domain seperator.\n\n### TokenIndex\n```\ntype TokenIndex = Nat32;\n```\nThis allows for 2\\*\\*32 unique tokens within a single canister (over 4 billion). This represents an individual token's index within a given canister.\n\n### Extension\n```\ntype Extension = Text;\n```\nExtensions are simply text fields, e.g. \"batch\", \"common\" and \"archive\".\n\n### Memo\n```\ntype Memo : Blob;\n```\nRepresents a \"payment\" memo/data which can be attached to a transaction. We hope that we can utilize native serialization/deserialization to allow for more advanced data to be stored in this way.\n\n### NotifyService\n```\ntype NotifyCallback = shared (TokenIdentifier, User, Balance, Memo) -\u003e async ?Balance;\ntype NotifyService = actor { tokenTransferNotification : NotifyCallback) -\u003e async ?Balance)};\n//e.g. (tokenId, from, amount, memo)\n```\nThis is the public call that a canister must contain to receive a transfer notification. The amount returned is the balance actually accepted. If a transaction request has `notify` set to true but the receiver does not have the correct NotifyCallback then the tx is cancelled.\n\n### Common Error\n```\ntype CommonError = {\n  #InvalidToken: TokenIdentifier;\n  #Other : Text;\n};\n```\nThe above represents a common error which can be returned.\n\n## Entry Points\n\n### extensions (query)\n```\nextensions : shared query () -\u003e async [Extension];\n```\nPublic query that returns an array of `Extension`s that the canister supports.\n\n### balance (query)\n```\ntype BalanceRequest = { \n  user : User; \n  token: TokenIdentifier;\n};\ntype BalanceResponse = Result\u003cBalance, CommonError\u003e;\n\nbalance: shared query (request : BalanceRequest) -\u003e async BalanceResponse;\n```\nPublic query that returns the `Balance` of a requested `User`, otherwise an error if it fails.\n\n### transfer\n```\ntype TransferRequest = {\n  from : User;\n  to : User;\n  token : TokenIdentifier;\n  amount : Balance;\n  memo : ?Memo;\n  notify : ?Bool;\n  subaccount : ?SubAccount;\n};\ntype TransferResponse = Result\u003cBalance, {\n  #Unauthorized: AccountIdentifier;\n  #InsufficientBalance;\n  #Rejected; //Rejected by canister\n  #InvalidToken: TokenIdentifier;\n  #CannotNotify: AccountIdentifier;\n  #Other : Text;\n}\u003e;\n\ntransfer: shared (request : TransferRequest) -\u003e async TransferResponse;\n```\nThis function attempts to transfer an `amount` of `token` between two users, `from` and `to`, with an optional `memo` (which is additional data specific to the transaction).\n\nIf `notify` is `true`, the canister will attempt to notify the recipient of the transaction (for which a response must be returned). This gives the recipient the power to reject a transaction if they wish. The recipient can also choose to only accept a partial transfer of tokens. Any rejected tokens are refunded to the sender.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FToniq-Labs%2Fextendable-token","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FToniq-Labs%2Fextendable-token","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FToniq-Labs%2Fextendable-token/lists"}