{"id":13762036,"url":"https://github.com/TENK-DAO/tenk","last_synced_at":"2025-05-10T14:31:19.221Z","repository":{"id":37091959,"uuid":"396132322","full_name":"TENK-DAO/tenk","owner":"TENK-DAO","description":"Template for making a NFT contract with a raffle of tokens","archived":false,"fork":false,"pushed_at":"2024-07-09T12:54:56.000Z","size":24003,"stargazers_count":49,"open_issues_count":9,"forks_count":33,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-09T17:59:37.905Z","etag":null,"topics":["ipfs","near","nft"],"latest_commit_sha":null,"homepage":"https://tenk-dao.github.io/tenk/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TENK-DAO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-08-14T21:14:35.000Z","updated_at":"2024-07-09T12:53:00.000Z","dependencies_parsed_at":"2024-01-13T03:29:18.135Z","dependency_job_id":null,"html_url":"https://github.com/TENK-DAO/tenk","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/TENK-DAO%2Ftenk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TENK-DAO%2Ftenk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TENK-DAO%2Ftenk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TENK-DAO%2Ftenk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TENK-DAO","download_url":"https://codeload.github.com/TENK-DAO/tenk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253428266,"owners_count":21906881,"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":["ipfs","near","nft"],"created_at":"2024-08-03T14:00:33.983Z","updated_at":"2025-05-10T14:31:14.213Z","avatar_url":"https://github.com/TENK-DAO.png","language":"TypeScript","funding_links":[],"categories":["Projects"],"sub_categories":["NFT"],"readme":"# Tenk NFT\n\nThis contract publishes collections of NFT for example 10,000, hence TenK.  Each time a token is minted it is randomly chosen from the remaining tokens. The core mechanism for this is a `Raffle` collection type, which allows randomly picking from a range without replacement. This contract also introduces the idea of using a linkdrop proxy to allow the owner or a normal user to \"pre-mint\" an item.\n\n## Details\n\nEach `token_id` is numbered in a range, e.g. `0-10,000`.  This each asset and its metadata then named correspondingly, e.g. `0.png`, `0.json`. These files are placed into a flat directory and added to IPFS.  This hash is used as the `base_uri` for the contract and all minted `token_id` can be used to find its corresponding file.\n\nFor example,\n\n- [https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link](https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link)\n- [https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link/42.png](https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link/42.png)\n- [https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link/42.json](https://bafybeiehqz6vklvxkopg3un3avdtevch4cywuihgxrb4oio2qgxf4764bi.ipfs.dweb.link/42.json)\n\n## Linkdrop proxy\n\nCurrently this project wraps its own linkdrop-proxy, but in the future it this will be its own contract that any contract use for the same ability to add a callback to be used when the linkdrop is claimed. When a linkdrop is created it reserves a raffle draw to be made when claiming. This allows the token to be a surprise (unless it's the last one).\n\n\n## API\n\nTypeScript docs are found at [https://tenk-dao.github.io/tenk/docs](https://tenk-dao.github.io/tenk/docs).\n\nCurrently there is no standard format to describe the types of a contract. One proposal is to use the [`wit` format](https://github.com/bytecodealliance/wit-bindgen/blob/main/WIT.md),\nwhich while intended as a tool to generate bindings that act as polyfill for [`WebAssembly Interface Types`](https://github.com/WebAssembly/interface-types), it provides a language agnostic\nway to describe types for the API of a Wasm Binary.\n\nThis work has led to the creation of [`witme`](https://github.com/ahalabs/witme), a tool for both generating a `.wit` document describing a Rust smart contract and generating a TypeScript file\nfrom a `.wit` document.  The generated TS file also includes a `Contract` class which handles calling the corresponding methods.\n\nFor example, `nft_transfer` generates the following three functions:\n\n```typescript\n\n// Will throw if there is an error and parse result if it exist.\nnft_transfer(args: {\n    receiver_id: AccountId;\n    token_id: TokenId;\n    approval_id?: u64;\n    memo?: string;\n}, options?: ChangeMethodOptions): Promise\u003cvoid\u003e;\n\n// Will return the response from the server regardless of it succeeded\nnft_transferRaw(args: {\n    receiver_id: AccountId;\n    token_id: TokenId;\n    approval_id?: u64;\n    memo?: string;\n}, options?: ChangeMethodOptions): Promise\u003cproviders.FinalExecutionOutcome\u003e;\n\n// Creates a function call action that can be added to a transaction\n// See the `./scripts/deploy.ts` for how this can be used\nnft_transferTx(args: {\n    receiver_id: AccountId;\n    token_id: TokenId;\n    approval_id?: u64;\n    memo?: string;\n}, options?: ChangeMethodOptions): transactions.Action;\n```\n\nHaving the types mean that your contract calls will be type checked and prevent failed transactions from missing or malformed arguments.\n\nView calls also generate a function.\n\n```typescript\n/// makes a view call and parses the result\nnft_payout(args: {\n    token_id: string;\n    balance: U128;\n    max_len_payout?: number;\n}, options?: ViewFunctionOptions): Promise\u003cPayout\u003e;\n\nnft_token(args: { token_id: TokenId;}, options?: ViewFunctionOptions): Promise\u003cToken | null\u003e;\n```\n\n\n### Using the contract's types\n\nThe main file and types of this package are found `./contracts/tenk/dist/*`\nand specified in the `package.json`. These\n\n\nFrom another TS project:\n\n```ts\nimport { Contract } from \"tenk-nft\"\n\n...\n\n\nasync function main({account}) {\n  const contract = new Contract(account, \"tenkv0.testnet.tenk\");\n\n  await contract.nft_transfer({receiver_id: \"eve.testnet\", token_id: \"0\"});\n  const token = await contract.nft_token({token_id: \"0\"})\n  console.log(`token ${token}`);\n}\n```\n\n## Using scripts with `near-cli`\n\nA recent update to `near-cli` allows passing a script the current context of the current `near` environment. This includes the account that is signing the transactions, access to the same `near-api-js` that the cli is using, and an array of arguments passed to the script.\n\nFor example, from the script [`update_royalties.ts`](./scripts/update_royalties.ts):\n\n```typescript\nimport {Context} from \"near-cli/context\";\nimport {Contract} from \"..\";\n\nexport async function main({ account, argv }: Context) {\n  let [contractId] = argv;\n  if (contractId === null) {\n    console.error(\"need to supply contract's accountId\")\n    console.error(\"... -- \u003ccontractId\u003e\")\n  }\n  let contract = new Contract(account, contractId);\n  const royalties = {\n    percent: 690,\n    accounts: {\n      \"tenk.sputnik-dao.near\": 2500,\n      \"bob.near\": 7500,\n    }\n  };\n  let res = await contract.update_royalties({ royalties });\n}\n```\n\nRun the script with `near-cil`'s `repl` command using the option `-s` to pass a script.  Other arguments of near-cli can be passed \nand any arguments after the `--` are collected in the passed `argv`.\n\n```bash\nnear repl -s ./scripts/update_royalties.ts --accountId owner.testnet -- contract.testnet\n```\n\nThis makes it easy to create your own near scripts, while still getting the benefit of type checking parameters.\n\n## Uploading Assets with [`nft-cli`](https://github.com/TENK-DAO/nft-cli)\n\n1. Have `NFT_STORAGE_API_TOKEN` env var set to api key from https://nft.storage\n1. Have assets numbered `0-x` with matching names `0.png` `0.json` in all in the same directory. E.g. `dir/0.png` `dir/0.json`.\n1. Install `nft-cli`: `npm install -g nft-cli`\n1. Pack assets with `nft pack dir --output nfts.car`\n1. Upload to nft.storage with `nft upload nfts.car`.  Optionaly can pass api token with `--api-key`\n\n## Aspects of Near that prevents hacks on this method of minting\n\nHere is [one example](https://cointelegraph.com/news/85-million-meebits-nft-project-exploited-attacker-nabs-700-000-collectible) of a \"hack\" that stole $85 million worth of nfts minted in a similar fasion. The \"attacker\" was able to map the NFT's id (our index) to its worth (its rarity). Then made a contract that made a cross contract call to mint an NFT, then canceling the transaction if it's not rare enough.  Though this cost the \"attacker\" $20K fees per hour, they were able to see the rare items and reap the reward.\n\nThe key aspect that this hack and others like it on Ethereum rely on is that a series of cross contract calls either succeed or fail. This way you can opt out of it before the end and goods never change hands.  On Near this is not the case.  Each cross contract call is asynchronous and can change the state.  This means when you use a cross contract call to mint a token and it succeeds, any money spent is gone and the token minted. Thus unlike the Ethereum example if you aren't satisfied with the token you received you can't choose to not receive it and not pay the owner.\n\n\n## NFT Standards\n\nFor more information about the API provided by the NFT standard see [nomicon.io](https://nomicon.io/Standards/NonFungibleToken).\n\n\n## Development\n\nThis project also aims to highlight the newest way to test smart contracts on near using [`near-workspaces`](https://github.com/near/workspaces-js).  See example tests in [`__test__`](./__test__).\n\nNode must be installed. And Rust must be install see [Getting Started in near-sdk.io](https://www.near-sdk.io/).\n\nTo build docs `witme` must be installed.\n\n```bash\ncargo install witme\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTENK-DAO%2Ftenk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTENK-DAO%2Ftenk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTENK-DAO%2Ftenk/lists"}