├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .github ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── codeql.yml │ ├── prettier.yml │ ├── release-package.yml │ └── run-tests.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .solhint.json ├── .solhintignore ├── CHANGELOG.md ├── LICENSE ├── NOTICE.md ├── README.md ├── contracts ├── RMRK │ ├── access │ │ ├── Ownable.sol │ │ └── OwnableLock.sol │ ├── catalog │ │ ├── IRMRKCatalog.sol │ │ └── RMRKCatalog.sol │ ├── core │ │ ├── IRMRKCore.sol │ │ └── RMRKCore.sol │ ├── emotable │ │ ├── IERC7409.sol │ │ └── RMRKEmotesRepository.sol │ ├── equippable │ │ ├── IERC6220.sol │ │ ├── RMRKEquippable.sol │ │ └── RMRKMinifiedEquippable.sol │ ├── extension │ │ ├── RMRKRoyalties.sol │ │ ├── multiAssetAutoIndex │ │ │ ├── IRMRKMultiAssetAutoIndex.sol │ │ │ └── RMRKMultiAssetAutoIndex.sol │ │ ├── nestableAutoIndex │ │ │ ├── IRMRKNestableAutoIndex.sol │ │ │ └── RMRKNestableAutoIndex.sol │ │ ├── reclaimableChild │ │ │ ├── IRMRKReclaimableChild.sol │ │ │ └── RMRKReclaimableChild.sol │ │ ├── revealable │ │ │ ├── IRMRKRevealable.sol │ │ │ ├── IRMRKRevealer.sol │ │ │ └── RMRKRevealable.sol │ │ ├── soulbound │ │ │ ├── IERC6454.sol │ │ │ ├── RMRKSoulbound.sol │ │ │ ├── RMRKSoulboundAfterBlockNumber.sol │ │ │ ├── RMRKSoulboundAfterTransactions.sol │ │ │ └── RMRKSoulboundPerToken.sol │ │ ├── tokenAttributes │ │ │ ├── IERC7508.sol │ │ │ └── RMRKTokenAttributesRepository.sol │ │ ├── tokenHolder │ │ │ ├── IERC7590.sol │ │ │ └── RMRKTokenHolder.sol │ │ └── typedMultiAsset │ │ │ ├── IRMRKTypedMultiAsset.sol │ │ │ └── RMRKTypedMultiAsset.sol │ ├── library │ │ ├── RMRKErrors.sol │ │ └── RMRKLib.sol │ ├── multiasset │ │ ├── AbstractMultiAsset.sol │ │ ├── IERC5773.sol │ │ └── RMRKMultiAsset.sol │ ├── nestable │ │ ├── IERC7401.sol │ │ ├── RMRKNestable.sol │ │ └── RMRKNestableMultiAsset.sol │ ├── security │ │ └── ReentrancyGuard.sol │ └── utils │ │ ├── IERC20.sol │ │ ├── IRMRKCollectionData.sol │ │ ├── RMRKBulkWriter.sol │ │ ├── RMRKBulkWriterPerCollection.sol │ │ ├── RMRKCatalogUtils.sol │ │ ├── RMRKCollectionUtils.sol │ │ ├── RMRKEquipRenderUtils.sol │ │ ├── RMRKMultiAssetRenderUtils.sol │ │ ├── RMRKNestableRenderUtils.sol │ │ └── RMRKRenderUtils.sol ├── implementations │ ├── abstract │ │ ├── RMRKAbstractEquippable.sol │ │ ├── RMRKAbstractMultiAsset.sol │ │ ├── RMRKAbstractNestable.sol │ │ └── RMRKAbstractNestableMultiAsset.sol │ ├── catalog │ │ ├── IRMRKCatalogExtended.sol │ │ ├── RMRKCatalogFactory.sol │ │ └── RMRKCatalogImpl.sol │ ├── lazyMintErc20 │ │ ├── InitDataERC20Pay.sol │ │ ├── RMRKEquippableLazyMintErc20.sol │ │ ├── RMRKEquippableLazyMintErc20Soulbound.sol │ │ ├── RMRKMultiAssetLazyMintErc20.sol │ │ ├── RMRKMultiAssetLazyMintErc20Soulbound.sol │ │ ├── RMRKNestableLazyMintErc20.sol │ │ ├── RMRKNestableLazyMintErc20Soulbound.sol │ │ ├── RMRKNestableMultiAssetLazyMintErc20.sol │ │ └── RMRKNestableMultiAssetLazyMintErc20Soulbound.sol │ ├── lazyMintNative │ │ ├── InitDataNativePay.sol │ │ ├── RMRKEquippableLazyMintNative.sol │ │ ├── RMRKEquippableLazyMintNativeSoulbound.sol │ │ ├── RMRKMultiAssetLazyMintNative.sol │ │ ├── RMRKMultiAssetLazyMintNativeSoulbound.sol │ │ ├── RMRKNestableLazyMintNative.sol │ │ ├── RMRKNestableLazyMintNativeSoulbound.sol │ │ ├── RMRKNestableMultiAssetLazyMintNative.sol │ │ └── RMRKNestableMultiAssetLazyMintNativeSoulbound.sol │ ├── premint │ │ ├── RMRKEquippablePreMint.sol │ │ ├── RMRKEquippablePreMintSoulbound.sol │ │ ├── RMRKMultiAssetPreMint.sol │ │ ├── RMRKMultiAssetPreMintSoulbound.sol │ │ ├── RMRKNestableMultiAssetPreMint.sol │ │ ├── RMRKNestableMultiAssetPreMintSoulbound.sol │ │ ├── RMRKNestablePreMint.sol │ │ └── RMRKNestablePreMintSoulbound.sol │ └── utils │ │ ├── RMRKImplementationBase.sol │ │ ├── RMRKRoyaltiesSplitter.sol │ │ ├── RMRKTokenURIEnumerated.sol │ │ └── RMRKTokenURIPerToken.sol ├── mocks │ ├── ERC20Mock.sol │ ├── ERC721Mock.sol │ ├── ERC721ReceiverMock.sol │ ├── OwnableLockMock.sol │ ├── OwnableMintableERC721Mock.sol │ ├── RMRKEquippableMock.sol │ ├── RMRKImplementationBaseMock.sol │ ├── RMRKMinifiedEquippableMock.sol │ ├── RMRKMultiAssetAutoIndexMock.sol │ ├── RMRKMultiAssetMock.sol │ ├── RMRKNestableAutoIndexMock.sol │ ├── RMRKNestableMock.sol │ ├── RMRKNestableMultiAssetMock.sol │ └── extensions │ │ ├── claimableChild │ │ └── RMRKNestableClaimableChildMock.sol │ │ ├── revealable │ │ ├── RMRKMultiAssetRevealableMock.sol │ │ └── RMRKRevealerMock.sol │ │ ├── soulbound │ │ ├── RMRKSoulboundEquippableMock.sol │ │ ├── RMRKSoulboundMultiAssetMock.sol │ │ ├── RMRKSoulboundNestableMock.sol │ │ ├── RMRKSoulboundNestableMultiAssetMock.sol │ │ └── RMRKSoulboundVariantMocks.sol │ │ ├── tokenHolder │ │ └── RMRKTokenHolderMock.sol │ │ └── typedMultiAsset │ │ ├── RMRKNestableTypedMultiAssetMock.sol │ │ ├── RMRKTypedEquippableMock.sol │ │ └── RMRKTypedMultiAssetMock.sol └── security_mocks │ └── ChildAdder.sol ├── docs ├── RMRK │ ├── access │ │ ├── Ownable.md │ │ └── OwnableLock.md │ ├── catalog │ │ ├── IRMRKCatalog.md │ │ └── RMRKCatalog.md │ ├── core │ │ ├── IRMRKCore.md │ │ └── RMRKCore.md │ ├── emotable │ │ ├── IERC7409.md │ │ └── RMRKEmotesRepository.md │ ├── equippable │ │ ├── IERC6220.md │ │ ├── RMRKEquippable.md │ │ └── RMRKMinifiedEquippable.md │ ├── extension │ │ ├── RMRKRoyalties.md │ │ ├── multiAssetAutoIndex │ │ │ ├── IRMRKMultiAssetAutoIndex.md │ │ │ └── RMRKMultiAssetAutoIndex.md │ │ ├── nestableAutoIndex │ │ │ ├── IRMRKNestableAutoIndex.md │ │ │ └── RMRKNestableAutoIndex.md │ │ ├── reclaimableChild │ │ │ ├── IRMRKReclaimableChild.md │ │ │ └── RMRKReclaimableChild.md │ │ ├── revealable │ │ │ ├── IRMRKRevealable.md │ │ │ ├── IRMRKRevealer.md │ │ │ └── RMRKRevealable.md │ │ ├── soulbound │ │ │ ├── IERC6454.md │ │ │ ├── RMRKSoulbound.md │ │ │ ├── RMRKSoulboundAfterBlockNumber.md │ │ │ ├── RMRKSoulboundAfterTransactions.md │ │ │ └── RMRKSoulboundPerToken.md │ │ ├── tokenAttributes │ │ │ ├── IERC7508.md │ │ │ └── RMRKTokenAttributesRepository.md │ │ ├── tokenHolder │ │ │ ├── IERC7590.md │ │ │ └── RMRKTokenHolder.md │ │ └── typedMultiAsset │ │ │ ├── IRMRKTypedMultiAsset.md │ │ │ └── RMRKTypedMultiAsset.md │ ├── library │ │ └── RMRKLib.md │ ├── multiasset │ │ ├── AbstractMultiAsset.md │ │ ├── IERC5773.md │ │ └── RMRKMultiAsset.md │ ├── nestable │ │ ├── IERC7401.md │ │ ├── RMRKNestable.md │ │ └── RMRKNestableMultiAsset.md │ ├── security │ │ └── ReentrancyGuard.md │ └── utils │ │ ├── IERC20.md │ │ ├── IRMRKCollectionData.md │ │ ├── RMRKBulkWriter.md │ │ ├── RMRKBulkWriterPerCollection.md │ │ ├── RMRKCatalogUtils.md │ │ ├── RMRKCollectionUtils.md │ │ ├── RMRKEquipRenderUtils.md │ │ ├── RMRKMultiAssetRenderUtils.md │ │ ├── RMRKNestableRenderUtils.md │ │ └── RMRKRenderUtils.md ├── console.md └── implementations │ ├── abstract │ ├── RMRKAbstractEquippable.md │ ├── RMRKAbstractMultiAsset.md │ ├── RMRKAbstractNestable.md │ └── RMRKAbstractNestableMultiAsset.md │ ├── catalog │ ├── IRMRKCatalogExtended.md │ ├── RMRKCatalogFactory.md │ └── RMRKCatalogImpl.md │ ├── lazyMintErc20 │ ├── InitDataERC20Pay.md │ ├── RMRKEquippableLazyMintErc20.md │ ├── RMRKEquippableLazyMintErc20Soulbound.md │ ├── RMRKMultiAssetLazyMintErc20.md │ ├── RMRKMultiAssetLazyMintErc20Soulbound.md │ ├── RMRKNestableLazyMintErc20.md │ ├── RMRKNestableLazyMintErc20Soulbound.md │ ├── RMRKNestableMultiAssetLazyMintErc20.md │ └── RMRKNestableMultiAssetLazyMintErc20Soulbound.md │ ├── lazyMintNative │ ├── InitDataNativePay.md │ ├── RMRKEquippableLazyMintNative.md │ ├── RMRKEquippableLazyMintNativeSoulbound.md │ ├── RMRKMultiAssetLazyMintNative.md │ ├── RMRKMultiAssetLazyMintNativeSoulbound.md │ ├── RMRKNestableLazyMintNative.md │ ├── RMRKNestableLazyMintNativeSoulbound.md │ ├── RMRKNestableMultiAssetLazyMintNative.md │ └── RMRKNestableMultiAssetLazyMintNativeSoulbound.md │ ├── premint │ ├── RMRKEquippablePreMint.md │ ├── RMRKEquippablePreMintSoulbound.md │ ├── RMRKMultiAssetPreMint.md │ ├── RMRKMultiAssetPreMintSoulbound.md │ ├── RMRKNestableMultiAssetPreMint.md │ ├── RMRKNestableMultiAssetPreMintSoulbound.md │ ├── RMRKNestablePreMint.md │ └── RMRKNestablePreMintSoulbound.md │ └── utils │ ├── RMRKImplementationBase.md │ ├── RMRKRoyaltiesSplitter.md │ ├── RMRKTokenURIEnumerated.md │ └── RMRKTokenURIPerToken.md ├── funding.json ├── hardhat.config.ts ├── img └── General_Overview_Modules.png ├── mythril-remappings.json ├── package.json ├── pnpm-lock.yaml ├── scripts ├── deploy-bulk-writer.ts ├── deploy-catalog-factory.ts ├── deploy-catalog-utils.ts ├── deploy-collection-utils.ts ├── deploy-emotable.ts ├── deploy-render-utils.ts ├── deploy-royalties-splitter.ts ├── deploy-token-attributes-repo.ts ├── generate-abis.ts └── utils.ts ├── test ├── behavior │ ├── catalog.ts │ ├── equippableAssets.ts │ ├── equippableParts.ts │ ├── equippableSlots.ts │ ├── erc721.ts │ ├── metadata.ts │ ├── mintingImpl.ts │ ├── multiasset.ts │ ├── nestable.ts │ ├── ownableLock.ts │ └── royalties.ts ├── bulkWriter.ts ├── catalogUtils.ts ├── collectionUtils.ts ├── emotableRepository.ts ├── equippable.ts ├── extensions │ ├── multiAssetAutoIndex.ts │ ├── nestableAutoIndex.ts │ ├── reclaimableChild.ts │ ├── revealable.ts │ ├── soulbound.ts │ ├── tokenAttributesRepository.ts │ ├── tokenHolder.ts │ └── typedMultiasset.ts ├── implementations │ ├── base.ts │ ├── catalog.ts │ ├── catalogFactory.ts │ ├── generalBehavior.ts │ ├── lazyMintErc20Pay.ts │ ├── lazyMintNativeTokenPay.ts │ └── premint.ts ├── interfaces.ts ├── kanariaUtils.ts ├── minifiedEquippable.ts ├── multiasset.ts ├── nestable.ts ├── nestableMultiasset.ts ├── nestableSecTests.ts ├── ownableLock.ts ├── renderUtils.ts ├── royaltiesSplitter.ts ├── setup │ ├── equippableParts.ts │ └── equippableSlots.ts └── utils.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | # Testing networks 2 | MOONBASE_URL= 3 | SEPOLIA_URL= 4 | MUMBAI_URL= 5 | BASE_GOERLI_URL= 6 | BASE_SEPOLIA_URL= 7 | SHIBUYA_URL= 8 | ZKATANA_URL= 9 | IMMUTABLE_TEST_URL= 10 | 11 | # Mainnet networks 12 | MOONRIVER_URL= 13 | MOONBEAM_URL= 14 | ETHEREUM_URL= 15 | POLYGON_URL= 16 | BASE_URL= 17 | ASTAR_URL= 18 | BSC_URL= 19 | 20 | # To verify contracts 21 | ETHERSCAN_API_KEY=ABC123 22 | MOONSCAN_APIKEY=ABC123 23 | POLYGONSCAN_API_KEY=ABC123 24 | BASESCAN_API_KEY=ABC123 25 | ASTAR_BLOCKSCOUT_API_KEY=ABC123 26 | ZKATANA_BLOCKSCOUT_API_KEY=ABC123 27 | BSCSCAN_API_KEY=ABC123 28 | IMMUTABLE_BLOCKSCOUT_API_KEY=ABC123 29 | 30 | # To report gas 31 | REPORT_GAS= 32 | COIN_MARKET_CAP_KEY= 33 | 34 | # To deploy contracts and interact with networks 35 | PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1 36 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: false, 4 | es2021: true, 5 | mocha: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'eslint:recommended', 10 | 'plugin:@typescript-eslint/eslint-recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | 'plugin:import/errors', 13 | 'plugin:import/typescript', 14 | ], 15 | parser: '@typescript-eslint/parser', 16 | parserOptions: { 17 | ecmaVersion: 12, 18 | }, 19 | rules: { 20 | 'import/no-duplicates': 0, 21 | 'import/no-unresolved': 2, 22 | 'import/extensions': [ 23 | 2, 24 | 'ignorePackages', 25 | { 26 | js: 'never', 27 | jsx: 'never', 28 | ts: 'never', 29 | tsx: 'never', 30 | }, 31 | ], 32 | 'node/no-extraneous-import': 0, 33 | 'node/no-missing-import': 0, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # The Github accounts listed here will automatically be requested to review PRs. 2 | * @steven2308 @Yuripetusko -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Describe the additions/improvements this PR contains. 4 | 5 | # Checklist 6 | 7 | - [ ] Verified code additions 8 | - [ ] Updated NatSpec comments (if applicable) 9 | - [ ] Regenerated docs 10 | - [ ] Ran prettier 11 | - [ ] Added tests to fully cover the changes 12 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # Name of this GitHub Actions workflow. 2 | name: Run Semgrep 3 | 4 | on: 5 | # Scan changed files in PRs (diff-aware scanning): 6 | pull_request: {} 7 | # On-demand 8 | workflow_dispatch: {} 9 | 10 | jobs: 11 | semgrep: 12 | # User-definable name of this GitHub Actions job: 13 | name: Scan 14 | # If you are self-hosting, change the following `runs-on` value: 15 | runs-on: ubuntu-latest 16 | 17 | container: 18 | # A Docker image with Semgrep installed. Do not change this. 19 | image: returntocorp/semgrep 20 | 21 | # Skip any PR created by dependabot to avoid permission issues: 22 | if: (github.actor != 'dependabot[bot]') 23 | 24 | steps: 25 | # Fetch project source with GitHub Actions Checkout. 26 | - uses: actions/checkout@v3 27 | # Fetch semgrep rules 28 | - name: Fetch semgrep rules 29 | uses: actions/checkout@v3 30 | with: 31 | repository: decurity/semgrep-smart-contracts 32 | path: rules 33 | # Run security and gas optimization rules 34 | - run: semgrep ci --sarif --output=semgrep.sarif || true 35 | env: 36 | SEMGREP_RULES: rules/solidity/security rules/solidity/performance 37 | # Upload findings to GitHub Advanced Security Dashboard 38 | - name: Upload findings to GitHub Advanced Security Dashboard 39 | uses: github/codeql-action/upload-sarif@v2 40 | with: 41 | sarif_file: semgrep.sarif 42 | if: always() 43 | -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | name: Auto format code with Prettier 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | prettier: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Run prettier 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: "18" 16 | - run: yarn install 17 | - run: yarn prettier 18 | -------------------------------------------------------------------------------- /.github/workflows/release-package.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: 18 15 | - run: npm ci 16 | - run: npm test 17 | 18 | publish-gpr: 19 | needs: build 20 | runs-on: ubuntu-latest 21 | permissions: 22 | packages: write 23 | contents: read 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: 18 29 | registry-url: https://npm.pkg.github.com/ 30 | - run: npm ci 31 | - run: npm publish 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 34 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Run unit tests 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: "18" 16 | - run: yarn install 17 | - run: npx hardhat test 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | temp 8 | .idea 9 | 10 | #Hardhat files 11 | cache 12 | artifacts 13 | 14 | #sec notes 15 | sec-review.md -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | hardhat.config.ts 2 | scripts 3 | test 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | "publishConfig": { 2 | "@rmrk-team:registry": "https://npm.pkg.github.com" 3 | } -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | docs 4 | typechain-types 5 | cache 6 | coverage* 7 | gasReporterOutput.json 8 | CHANGELOG.md -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-solidity"], 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": "*.sol", 7 | "options": { 8 | "printWidth": 80, 9 | "tabWidth": 4, 10 | "useTabs": false, 11 | "singleQuote": false, 12 | "bracketSpacing": false, 13 | "compiler": "0.8.21" 14 | } 15 | }, 16 | { 17 | "files": ["*.ts", "*.js"], 18 | "options": { 19 | "trailingComma": "all", 20 | "singleQuote": true, 21 | "bracketSpacing": true, 22 | "parser": "typescript", 23 | "printWidth": 100, 24 | "tabWidth": 2, 25 | "useTabs": false, 26 | "semi": true 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", "^0.8.0"], 5 | "func-visibility": ["warn", { "ignoreConstructors": true }] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | Any derivative software shall both in code and in terminal or 2 | command line output contain the following disclaimer, verbatim 3 | 4 | /***********************************************/ 5 | /** Using software by RMRK.app **/ 6 | /** contact@rmrk.app **/ 7 | /***********************************************/ 8 | 9 | Should RMRK technology be used this must be clearly 10 | stated in an obvious location (e.g. footer), in the following 11 | way: `Using software by RMRK.app | contact@rmrk.app` and if 12 | technically possible, the part “RMRK.app" must be hyperlinked 13 | to https://rmrk.app. Implementers may approach the RMRK team 14 | via contact@rmrk.app for alternative ways of expressing 15 | attribution. 16 | 17 | The above two conditions may be waived on a case by case basis 18 | by obtaining a written whitelabel permission from the RMRK team 19 | via contact through contact@rmrk.app 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RMRK EVM Package 2 | 3 | A set of Solidity smart contracts implementing [RMRK](https://rmrk.app) modular NFTs and compatible extensions for them. 4 | 5 | **Smart contracts documentation as well as usage instructions and tutorials can be found in the 6 | [RMRK EVM developer documentation](https://evm.rmrk.app)** 7 | 8 | ## Usage 9 | 10 | To use the RMRK legos and smart contracts contained in this repository, simply add them to your project: 11 | 12 | ```shell 13 | yarn add @rmrk-team/evm-contracts 14 | ``` 15 | 16 | or 17 | 18 | ```shell 19 | npm -i @rmrk-team/evm-contracts 20 | ``` 21 | 22 | Once the dependency is added to your project, simply import the smart contracts you wish to utilize into your own smart 23 | contract. 24 | 25 | ## RMRK Legos 26 | 27 | RMRK is a set of NFT standards that compose several NFT module primitives. Putting these modules together allows a user to create NFT systems of arbitrary complexity. 28 | So far we have created 6 modules as ERC proposals, all of which are ERC721 compatible. The first 5 are already standards, the 6th is still in Draft. 29 | 30 | - MultiAsset: [ERC-5773: Context-Dependent Multi-Asset Tokens](https://eips.ethereum.org/EIPS/eip-5773) 31 | - Nestable: [ERC-7401: Parent-Governed Non-Fungible Tokens Nesting](https://eips.ethereum.org/EIPS/eip-7401) 32 | - Composable & Equippable: [ERC-6220: Composable NFTs utilizing Equippable Parts](https://eips.ethereum.org/EIPS/eip-6220) 33 | - Soulbound: [ERC-6454: Minimal Transferable NFT detection interface](https://eips.ethereum.org/EIPS/eip-6454) 34 | - Emotable: [ERC-7409: Public Non-Fungible Tokens Emote Repository](https://eips.ethereum.org/EIPS/eip-7409) 35 | - Dynamic Attributes: [ERC-7508: Dynamic On-Chain Token Attributes Repository ](https://eips.ethereum.org/EIPS/eip-7508) 36 | - ERC20-Holder: [ERC-7590: ERC-20 Holder Extension for NFTs ](https://eips.ethereum.org/EIPS/eip-7590) 37 | 38 | ![RMRK Modules](/img/General_Overview_Modules.png) 39 | -------------------------------------------------------------------------------- /contracts/RMRK/access/OwnableLock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {Ownable} from "./Ownable.sol"; 6 | import "../library/RMRKErrors.sol"; 7 | 8 | /** 9 | * @title OwnableLock 10 | * @author RMRK team 11 | * @notice A minimal ownable lock smart contract. 12 | */ 13 | contract OwnableLock is Ownable { 14 | uint256 private _lock; 15 | 16 | /** 17 | * @notice Emitted when the smart contract is locked. 18 | */ 19 | event LockSet(); 20 | 21 | /** 22 | * @notice Reverts if the lock flag is set to true. 23 | */ 24 | modifier notLocked() { 25 | _onlyNotLocked(); 26 | _; 27 | } 28 | 29 | /** 30 | * @notice Locks the operation. 31 | * @dev Once locked, functions using `notLocked` modifier cannot be executed. 32 | * @dev Emits ***LockSet*** event. 33 | */ 34 | function setLock() public virtual onlyOwner { 35 | _lock = 1; 36 | emit LockSet(); 37 | } 38 | 39 | /** 40 | * @notice Used to retrieve the status of a lockable smart contract. 41 | * @return isLocked A boolean value signifying whether the smart contract has been locked 42 | */ 43 | function getLock() public view returns (bool isLocked) { 44 | isLocked = _lock == 1; 45 | } 46 | 47 | /** 48 | * @notice Used to verify that the operation of the smart contract is not locked. 49 | * @dev If the operation of the smart contract is locked, the execution will be reverted. 50 | */ 51 | function _onlyNotLocked() private view { 52 | if (_lock == 1) revert RMRKLocked(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contracts/RMRK/core/IRMRKCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title IRMRKCore 7 | * @author RMRK team 8 | * @notice Interface smart contract for RMRK core module. 9 | */ 10 | interface IRMRKCore { 11 | /** 12 | * @notice Used to retrieve the collection name. 13 | * @return Name of the collection 14 | */ 15 | function name() external view returns (string memory); 16 | 17 | /** 18 | * @notice Used to retrieve the collection symbol. 19 | * @return Symbol of the collection 20 | */ 21 | function symbol() external view returns (string memory); 22 | } 23 | -------------------------------------------------------------------------------- /contracts/RMRK/core/RMRKCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title RMRKCore 7 | * @author RMRK team 8 | * @notice Smart contract of the RMRK core module. 9 | * @dev This is currently just a passthrough contract which allows for granular editing of base-level ERC721 functions. 10 | */ 11 | contract RMRKCore { 12 | string private constant _VERSION = "2.5.3"; 13 | bytes4 private constant _RMRK_INTERFACE = 0x524D524B; // "RMRK" in ASCII hex 14 | 15 | /** 16 | * @notice Version of the @rmrk-team/evm-contracts package 17 | * @return version Version identifier for implementations of the @rmrk-team/evm-contracts package 18 | */ 19 | function VERSION() public pure returns (string memory version) { 20 | version = _VERSION; 21 | } 22 | 23 | /** 24 | * @notice Interface identifier of the @rmrk-team/evm-contracts package 25 | * @return rmrkInterface Interface identifier for implementations of the @rmrk-team/evm-contracts package 26 | */ 27 | function RMRK_INTERFACE() public pure returns (bytes4 rmrkInterface) { 28 | rmrkInterface = _RMRK_INTERFACE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/RMRKRoyalties.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol"; 6 | import "../library/RMRKErrors.sol"; 7 | 8 | /** 9 | * @title RMRKRoyalties 10 | * @author RMRK team 11 | * @notice Smart contract of the RMRK Royalties module. 12 | */ 13 | abstract contract RMRKRoyalties { 14 | /** is IERC2981 **/ // Inheritance is commmnted to prevent linearization issues 15 | address private _royaltyRecipient; 16 | uint256 private _royaltyPercentageBps; 17 | 18 | /** 19 | * @notice Used to initiate the smart contract. 20 | * @dev `royaltyPercentageBps` is expressed in basis points, so 1 basis point equals 0.01% and 500 basis points 21 | * equal 5%. 22 | * @param royaltyRecipient Address to which royalties should be sent 23 | * @param royaltyPercentageBps The royalty percentage expressed in basis points 24 | */ 25 | constructor(address royaltyRecipient, uint256 royaltyPercentageBps) { 26 | _setRoyaltyRecipient(royaltyRecipient); 27 | if (royaltyPercentageBps >= 10000) revert RMRKRoyaltiesTooHigh(); 28 | _royaltyPercentageBps = royaltyPercentageBps; 29 | } 30 | 31 | /** 32 | * @notice Used to update recipient of royalties. 33 | * @dev Custom access control has to be implemented to ensure that only the intended actors can update the 34 | * beneficiary. 35 | * @param newRoyaltyRecipient Address of the new recipient of royalties 36 | */ 37 | function updateRoyaltyRecipient( 38 | address newRoyaltyRecipient 39 | ) external virtual; 40 | 41 | /** 42 | * @notice Used to update the royalty recipient. 43 | * @param newRoyaltyRecipient Address of the new recipient of royalties 44 | */ 45 | function _setRoyaltyRecipient(address newRoyaltyRecipient) internal { 46 | _royaltyRecipient = newRoyaltyRecipient; 47 | } 48 | 49 | /** 50 | * @notice Used to retrieve the recipient of royalties. 51 | * @return recipient Address of the recipient of royalties 52 | */ 53 | function getRoyaltyRecipient() 54 | public 55 | view 56 | virtual 57 | returns (address recipient) 58 | { 59 | recipient = _royaltyRecipient; 60 | } 61 | 62 | /** 63 | * @notice Used to retrieve the specified royalty percentage. 64 | * @return royaltyPercentageBps The royalty percentage expressed in the basis points 65 | */ 66 | function getRoyaltyPercentage() 67 | public 68 | view 69 | virtual 70 | returns (uint256 royaltyPercentageBps) 71 | { 72 | royaltyPercentageBps = _royaltyPercentageBps; 73 | } 74 | 75 | /** 76 | * @notice Used to retrieve the information about who shall receive royalties of a sale of the specified token and 77 | * how much they will be. 78 | * @param tokenId ID of the token for which the royalty info is being retrieved 79 | * @param salePrice Price of the token sale 80 | * @return receiver The beneficiary receiving royalties of the sale 81 | * @return royaltyAmount The value of the royalties recieved by the `receiver` from the sale 82 | */ 83 | function royaltyInfo( 84 | uint256 tokenId, 85 | uint256 salePrice 86 | ) external view virtual returns (address receiver, uint256 royaltyAmount) { 87 | uint256(tokenId); // Silence the warning about unused variable, needed for docs generation 88 | receiver = _royaltyRecipient; 89 | royaltyAmount = (salePrice * _royaltyPercentageBps) / 10000; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/multiAssetAutoIndex/IRMRKMultiAssetAutoIndex.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC5773} from "../../multiasset/IERC5773.sol"; 6 | 7 | /** 8 | * @title RMRKMultiAssetAutoIndex 9 | * @author RMRK team 10 | * @notice Interface smart contract of the RMRK MultiAsset AutoIndex module. 11 | */ 12 | interface IRMRKMultiAssetAutoIndex is IERC5773 { 13 | /** 14 | * @notice Accepts an asset from the pending array of given token. 15 | * @dev Migrates the asset from the token's pending asset array to the token's active asset array. 16 | * @dev An active asset cannot be removed by anyone, but can be replaced by a new asset. 17 | * @dev Requirements: 18 | * 19 | * - The caller must own the token or be approved to manage the token's assets 20 | * - `tokenId` must exist. 21 | * @dev Emits an {AssetAccepted} event. 22 | * @param tokenId ID of the token for which to accept the pending asset 23 | * @param assetId Id of the pending asset 24 | */ 25 | function acceptAsset(uint256 tokenId, uint64 assetId) external; 26 | 27 | /** 28 | * @notice Rejects an asset from the pending array of given token. 29 | * @dev Removes the asset from the token's pending asset array. 30 | * @dev Requirements: 31 | * 32 | * - The caller must own the token or be approved to manage the token's assets 33 | * - `tokenId` must exist. 34 | * @dev Emits a {AssetRejected} event. 35 | * @param tokenId ID of the token that the asset is being rejected from 36 | * @param assetId Id of the pending asset 37 | */ 38 | function rejectAsset(uint256 tokenId, uint64 assetId) external; 39 | } 40 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/nestableAutoIndex/IRMRKNestableAutoIndex.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC7401} from "../../nestable/IERC7401.sol"; 6 | 7 | /** 8 | * @title RMRKNestableAutoIndex 9 | * @author RMRK team 10 | * @notice Interface smart contract of the RMRK Nestable AutoIndex module. 11 | */ 12 | interface IRMRKNestableAutoIndex is IERC7401 { 13 | /** 14 | * @notice Used to accept a pending child token for a given parent token. 15 | * @dev This moves the child token from parent token's pending child tokens array into the active child tokens 16 | * array. 17 | * @param parentId ID of the parent token for which the child token is being accepted 18 | * @param childAddress Address of the collection smart contract of the child 19 | * @param childId ID of the child token 20 | */ 21 | function acceptChild( 22 | uint256 parentId, 23 | address childAddress, 24 | uint256 childId 25 | ) external; 26 | 27 | /** 28 | * @notice Used to transfer a child token from a given parent token. 29 | * @dev When transferring a child token, the owner of the token is set to `to`, or is not updated in the event of `to` 30 | * being the `0x0` address. 31 | * @param tokenId ID of the parent token from which the child token is being transferred 32 | * @param to Address to which to transfer the token to 33 | * @param destinationId ID of the token to receive this child token (MUST be 0 if the destination is not a token) 34 | * @param childAddress Address of the collection smart contract of the child 35 | * @param childId ID of the child token 36 | * @param isPending A boolean value indicating whether the child token being transferred is in the pending array of the 37 | * parent token (`true`) or in the active array (`false`) 38 | * @param data Additional data with no specified format, sent in call to `_to` 39 | */ 40 | function transferChild( 41 | uint256 tokenId, 42 | address to, 43 | uint256 destinationId, 44 | address childAddress, 45 | uint256 childId, 46 | bool isPending, 47 | bytes memory data 48 | ) external; 49 | } 50 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/reclaimableChild/IRMRKReclaimableChild.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | 7 | /** 8 | * @title IRMRKReclaimableChild 9 | * @author RMRK team 10 | * @notice Interface smart contract of the RMRK Reclaimable child module. 11 | */ 12 | interface IRMRKReclaimableChild is IERC165 { 13 | /** 14 | * @notice Used to reclaim an abandoned child token. 15 | * @dev Child token was abandoned by transferring it with `to` as the `0x0` address. 16 | * @dev This function will set the child's owner to the `rootOwner` of the caller, allowing the `rootOwner` 17 | * management permissions for the child. 18 | * @dev Requirements: 19 | * 20 | * - `tokenId` must exist 21 | * @param tokenId ID of the last parent token of the child token being recovered 22 | * @param childAddress Address of the child token's smart contract 23 | * @param childId ID of the child token being reclaimed 24 | */ 25 | function reclaimChild( 26 | uint256 tokenId, 27 | address childAddress, 28 | uint256 childId 29 | ) external; 30 | } 31 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/revealable/IRMRKRevealable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | interface IRMRKRevealable { 6 | /** 7 | * @notice Gets the `IRMRKRevealer` associated with the contract. 8 | * @return revealer The `IRMRKRevealer` associated with the contract 9 | */ 10 | function getRevealer() external view returns (address revealer); 11 | 12 | /** 13 | * @notice Sets the `IRMRKRevealer` associated with the contract. 14 | * @param revealer The `IRMRKRevealer` to associate with the contract 15 | */ 16 | function setRevealer(address revealer) external; 17 | 18 | /** @notice Reveals the asset for the given tokenIds by adding and accepting and new one. 19 | * @dev SHOULD ask revealer which assetId should be added to the token and which asset to replace through `IRMRKRevealer.getAssetsToReveal` 20 | * @dev SHOULD be called by the owner or approved for assets 21 | * @dev SHOULD add the new asset to each token and accept it 22 | */ 23 | function reveal(uint256[] memory tokenIds) external; 24 | } 25 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/revealable/IRMRKRevealer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | interface IRMRKRevealer { 6 | event Revealed( 7 | uint256[] indexed tokenIds, 8 | uint64[] revealedAssetsIds, 9 | uint64[] assetsToReplaceIds 10 | ); 11 | 12 | /** 13 | * @notice For each `tokenId` in `tokenIds` returns whether it can be revealed or not 14 | * @param tokenIds The `tokenIds` to check 15 | * @return revealable The array of booleans indicating whether each `tokenId` can be revealed or not 16 | */ 17 | function getRevealableTokens( 18 | uint256[] memory tokenIds 19 | ) external view returns (bool[] memory revealable); 20 | 21 | /** 22 | * @notice Returns the revealed `assetIds` for the given `tokenIds` and marks them as revealed. 23 | * @param tokenIds The `tokenIds` to reveal 24 | * @dev This CAN add new assets to the original contract if necessary, in which case it SHOULD have the necessary permissions 25 | * @dev This method MUST only return existing `assetIds` 26 | * @dev This method MUST be called only by the contract implementing the `IRMRKRevealable` interface, during the `reveal` method 27 | * @dev This method MUST return the same amount of `revealedAssetsIds` and `assetsToReplaceIds` as `tokenIds` 28 | * @return revealedAssetsIds The revealed `assetIds` 29 | * @return assetsToReplaceIds The `assetIds` to replace 30 | */ 31 | function reveal( 32 | uint256[] memory tokenIds 33 | ) 34 | external 35 | returns ( 36 | uint64[] memory revealedAssetsIds, 37 | uint64[] memory assetsToReplaceIds 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/revealable/RMRKRevealable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | import {IRMRKRevealable} from "./IRMRKRevealable.sol"; 4 | import {IRMRKRevealer} from "./IRMRKRevealer.sol"; 5 | 6 | pragma solidity ^0.8.21; 7 | 8 | /** 9 | * @title IRMRKRevealable 10 | * @author RMRK team 11 | * @notice Interface smart contract of the RMRK Revealable extension. This extension simplifies the process of revealing. 12 | */ 13 | abstract contract RMRKRevealable is IRMRKRevealable { 14 | address private _revealer; 15 | 16 | /** 17 | * @notice Returns the address of the revealer contract 18 | */ 19 | function getRevealer() external view returns (address) { 20 | return _revealer; 21 | } 22 | 23 | /** 24 | * @notice Sets the revealer contract address 25 | */ 26 | function _setRevealer(address revealer) internal { 27 | _revealer = revealer; 28 | } 29 | 30 | /** 31 | * @notice Reveals the assets for the given tokenIds 32 | * @param tokenIds The tokenIds to reveal 33 | * @dev This method SHOULD be called by the owner or approved for assets 34 | * @dev This method SHOULD add the asset to the token and accept it 35 | * @dev This method SHOULD get the `assetId` to add and replace from the revealer contract 36 | * @dev This `assetId` to replace CAN be 0, meaning that the asset is added to the token without replacing anything 37 | * @dev The revealer contract MUST take care of ensuring the `assetId` exists on the contract implementating this interface 38 | */ 39 | function reveal(uint256[] memory tokenIds) external { 40 | _checkRevealPermissions(tokenIds); 41 | uint256 length = tokenIds.length; 42 | ( 43 | uint64[] memory revealedAssetsIds, 44 | uint64[] memory assetsToReplaceIds 45 | ) = IRMRKRevealer(_revealer).reveal(tokenIds); 46 | for (uint256 i; i < length; ) { 47 | _addAndAcceptAssetToToken( 48 | tokenIds[i], 49 | revealedAssetsIds[i], 50 | assetsToReplaceIds[i] 51 | ); 52 | unchecked { 53 | ++i; 54 | } 55 | } 56 | } 57 | 58 | function supportsInterface( 59 | bytes4 interfaceId 60 | ) public view virtual returns (bool) { 61 | return interfaceId == type(IRMRKRevealable).interfaceId; 62 | } 63 | 64 | /** 65 | * @notice Adds the asset to the token and accepts it. 66 | * @param tokenId The tokenId to add the asset to 67 | * @param newAssetId The assetId to add 68 | * @param assetToReplaceId The assetId to replace. Might be 0, meaning that the asset is added to the token without replacing anything 69 | */ 70 | function _addAndAcceptAssetToToken( 71 | uint256 tokenId, 72 | uint64 newAssetId, 73 | uint64 assetToReplaceId 74 | ) internal virtual { 75 | // Expected implementation: 76 | // _addAssetToToken(tokenId, newAssetId, assetToReplaceId); 77 | // _acceptAsset(tokenId, _pendingAssets[tokenId].length - 1, newAssetId); 78 | } 79 | 80 | /** 81 | * @notice Checks that the msg sender has permissions to reveal the given tokenIds 82 | * @dev The caller SHOULD be either the owner or approved for assets. 83 | * @param tokenIds The tokenIds to reveal 84 | */ 85 | function _checkRevealPermissions( 86 | uint256[] memory tokenIds 87 | ) internal view virtual { 88 | // Expected implementation: 89 | // uint256 length = tokenIds.length; 90 | // for (uint256 i; i < length; ) { 91 | // _onlyApprovedForAssetsOrOwner(tokenIds[i]); 92 | // unchecked { 93 | // ++i; 94 | // } 95 | // } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/soulbound/IERC6454.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | 7 | /** 8 | * @title IERC6454 9 | * @author RMRK team 10 | * @notice A minimal extension to identify the transferability of Non-Fungible Tokens. 11 | */ 12 | interface IERC6454 is IERC165 { 13 | /** 14 | * @notice Used to check whether the given token is transferable or not. 15 | * @dev If this function returns `false`, the transfer of the token MUST revert execution. 16 | * @dev If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for 17 | * minting. 18 | * @param tokenId ID of the token being checked 19 | * @param from Address from which the token is being transferred 20 | * @param to Address to which the token is being transferred 21 | * @return isTransferable_ Boolean value indicating whether the given token is transferable 22 | */ 23 | function isTransferable( 24 | uint256 tokenId, 25 | address from, 26 | address to 27 | ) external view returns (bool isTransferable_); 28 | } 29 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/soulbound/RMRKSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC6454} from "./IERC6454.sol"; 6 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 7 | import "../../library/RMRKErrors.sol"; 8 | 9 | /** 10 | * @title RMRKSoulbound 11 | * @author RMRK team 12 | * @notice Smart contract of the RMRK Soulbound module. 13 | */ 14 | abstract contract RMRKSoulbound is IERC6454 { 15 | /** 16 | * @notice Hook that is called before any token transfer. This includes minting and burning. 17 | * @dev This is a hook ensuring that all transfers of tokens are reverted if the token is soulbound. 18 | * @dev The only exception of transfers being allowed is when the tokens are minted or when they are being burned. 19 | * @param from Address from which the token is originating (current owner of the token) 20 | * @param to Address to which the token would be sent 21 | * @param tokenId ID of the token that would be transferred 22 | */ 23 | function _beforeTokenTransfer( 24 | address from, 25 | address to, 26 | uint256 tokenId 27 | ) internal virtual { 28 | if (!isTransferable(tokenId, from, to)) 29 | revert RMRKCannotTransferSoulbound(); 30 | } 31 | 32 | /** 33 | * @inheritdoc IERC6454 34 | */ 35 | function isTransferable( 36 | uint256, 37 | address from, 38 | address to 39 | ) public view virtual returns (bool isTransferable_) { 40 | isTransferable_ = ((from == address(0) || // Exclude minting 41 | to == address(0)) && from != to); // Exclude Burning // Besides the obvious transfer to self, if both are address 0 (general transferability check), it returns false 42 | } 43 | 44 | /** 45 | * @inheritdoc IERC165 46 | */ 47 | function supportsInterface( 48 | bytes4 interfaceId 49 | ) public view virtual returns (bool) { 50 | return interfaceId == type(IERC6454).interfaceId; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/soulbound/RMRKSoulboundAfterBlockNumber.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC6454} from "./IERC6454.sol"; 6 | import {RMRKSoulbound} from "./RMRKSoulbound.sol"; 7 | 8 | /** 9 | * @title RMRKSoulboundAfterBlockNumber 10 | * @author RMRK team 11 | * @notice Smart contract of the RMRK Soulbound module where transfers are only allowed until a certain block number. 12 | */ 13 | abstract contract RMRKSoulboundAfterBlockNumber is RMRKSoulbound { 14 | // Last block number where transfers are allowed 15 | uint256 private _lastBlockToTransfer; 16 | 17 | /** 18 | * @notice Used to initialize the smart contract. 19 | * @param lastBlockToTransfer Last block number where transfers are allowed 20 | */ 21 | constructor(uint256 lastBlockToTransfer) { 22 | _lastBlockToTransfer = lastBlockToTransfer; 23 | } 24 | 25 | /** 26 | * @notice Gets the last block number where transfers are allowed 27 | * @return The block number after which tokens are soulbound 28 | */ 29 | function getLastBlockToTransfer() public view returns (uint256) { 30 | return _lastBlockToTransfer; 31 | } 32 | 33 | /** 34 | * @inheritdoc IERC6454 35 | */ 36 | function isTransferable( 37 | uint256, 38 | address, 39 | address 40 | ) public view virtual override returns (bool isTransferable_) { 41 | isTransferable_ = _lastBlockToTransfer > block.number; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/soulbound/RMRKSoulboundAfterTransactions.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC6454} from "./IERC6454.sol"; 6 | import {RMRKSoulbound} from "./RMRKSoulbound.sol"; 7 | 8 | /** 9 | * @title RMRKSoulboundAfterTransactions 10 | * @author RMRK team 11 | * @notice Smart contract of the RMRK Soulbound module where transfers are allowed for a limited a number of transfers. 12 | */ 13 | abstract contract RMRKSoulboundAfterTransactions is RMRKSoulbound { 14 | /** 15 | * @notice Emitted when a token becomes soulbound. 16 | * @param tokenId ID of the token 17 | */ 18 | event Soulbound(uint256 indexed tokenId); 19 | 20 | // Max number of transfers before a token becomes soulbound 21 | uint256 private _maxNumberOfTransfers; 22 | // Mapping of token ID to number of transfers 23 | mapping(uint256 => uint256) private _transfersPerToken; 24 | 25 | /** 26 | * @notice Used to initialize the smart contract. 27 | * @param maxNumberOfTransfers Max number of transfers before a token becomes soulbound 28 | */ 29 | constructor(uint256 maxNumberOfTransfers) { 30 | _maxNumberOfTransfers = maxNumberOfTransfers; 31 | } 32 | 33 | /** 34 | * @notice Hook that is called after any transfer of tokens. This includes minting and burning. 35 | * @dev Calling conditions: 36 | * 37 | * - When `from` and `to` are both non-zero. 38 | * - `from` and `to` are never zero at the same time. 39 | * 40 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 41 | * @param from Address from which the token has been transferred 42 | * @param to Address to which the token has been transferred 43 | * @param tokenId ID of the token that has been transferred 44 | */ 45 | function _afterTokenTransfer( 46 | address from, 47 | address to, 48 | uint256 tokenId 49 | ) internal virtual { 50 | address(to); // Silence the warning about unused variable, needed for docs generation 51 | // We won't count minting: 52 | if (from != address(0)) { 53 | _transfersPerToken[tokenId]++; 54 | emit Soulbound(tokenId); 55 | } 56 | } 57 | 58 | /** 59 | * @notice Gets the maximum number of transfers before a token becomes soulbound. 60 | * @return Maximum number of transfers before a token becomes soulbound 61 | */ 62 | function getMaxNumberOfTransfers() public view returns (uint256) { 63 | return _maxNumberOfTransfers; 64 | } 65 | 66 | /** 67 | * @notice Gets the current number of transfer the specified token. 68 | * @param tokenId ID of the token 69 | * @return Number of the token's transfers to date 70 | */ 71 | function getTransfersPerToken( 72 | uint256 tokenId 73 | ) public view returns (uint256) { 74 | return _transfersPerToken[tokenId]; 75 | } 76 | 77 | /** 78 | * @inheritdoc IERC6454 79 | */ 80 | function isTransferable( 81 | uint256 tokenId, 82 | address, 83 | address 84 | ) public view virtual override returns (bool isTransferable_) { 85 | isTransferable_ = _transfersPerToken[tokenId] < _maxNumberOfTransfers; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/soulbound/RMRKSoulboundPerToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC6454} from "./IERC6454.sol"; 6 | import {RMRKSoulbound} from "./RMRKSoulbound.sol"; 7 | 8 | /** 9 | * @title RMRKSoulboundPerToken 10 | * @author RMRK team 11 | * @notice Smart contract of the RMRK Soulbound module where the transfers are permitted or prohibited on a per-token basis. 12 | */ 13 | abstract contract RMRKSoulboundPerToken is RMRKSoulbound { 14 | /** 15 | * @notice Emitted when a token's soulbound state changes. 16 | * @param tokenId ID of the token 17 | * @param state A boolean value signifying whether the token became soulbound (`true`) or transferrable (`false`) 18 | */ 19 | event Soulbound(uint256 indexed tokenId, bool state); 20 | 21 | // Mapping of token ID to soulbound state 22 | mapping(uint256 => bool) private _isSoulbound; 23 | 24 | /** 25 | * @notice Sets the soulbound state of a token. 26 | * @dev Custom access control has to be implemented when exposing this method in a smart contract that utillizes it. 27 | * @param tokenId ID of the token 28 | * @param state New soulbound state 29 | */ 30 | function _setSoulbound(uint256 tokenId, bool state) internal virtual { 31 | _isSoulbound[tokenId] = state; 32 | emit Soulbound(tokenId, state); 33 | } 34 | 35 | /** 36 | * @inheritdoc IERC6454 37 | */ 38 | function isTransferable( 39 | uint256 tokenId, 40 | address from, 41 | address to 42 | ) public view virtual override returns (bool isTransferable_) { 43 | isTransferable_ = (from == address(0) || // Exclude minting 44 | to == address(0) || // Exclude Burning 45 | !_isSoulbound[tokenId]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/tokenHolder/IERC7590.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | 7 | interface IERC7590 is IERC165 { 8 | /** 9 | * @notice Used to notify listeners that the token received ERC-20 tokens. 10 | * @param erc20Contract The address of the ERC-20 smart contract 11 | * @param toTokenId The ID of the token receiving the ERC-20 tokens 12 | * @param from The address of the account from which the tokens are being transferred 13 | * @param amount The number of ERC-20 tokens received 14 | */ 15 | event ReceivedERC20( 16 | address indexed erc20Contract, 17 | uint256 indexed toTokenId, 18 | address indexed from, 19 | uint256 amount 20 | ); 21 | 22 | /** 23 | * @notice Used to notify the listeners that the ERC-20 tokens have been transferred. 24 | * @param erc20Contract The address of the ERC-20 smart contract 25 | * @param fromTokenId The ID of the token from which the ERC-20 tokens have been transferred 26 | * @param to The address receiving the ERC-20 tokens 27 | * @param amount The number of ERC-20 tokens transferred 28 | */ 29 | event TransferredERC20( 30 | address indexed erc20Contract, 31 | uint256 indexed fromTokenId, 32 | address indexed to, 33 | uint256 amount 34 | ); 35 | 36 | /** 37 | * @notice Used to retrieve the given token's specific ERC-20 balance 38 | * @param erc20Contract The address of the ERC-20 smart contract 39 | * @param tokenId The ID of the token being checked for ERC-20 balance 40 | * @return The amount of the specified ERC-20 tokens owned by a given token 41 | */ 42 | function balanceOfERC20( 43 | address erc20Contract, 44 | uint256 tokenId 45 | ) external view returns (uint256); 46 | 47 | /** 48 | * @notice Transfer ERC-20 tokens from a specific token. 49 | * @dev The balance MUST be transferred from this smart contract. 50 | * @dev MUST increase the transfer-out-nonce for the tokenId 51 | * @dev MUST revert if the `msg.sender` is not the owner of the NFT or approved to manage it. 52 | * @param erc20Contract The address of the ERC-20 smart contract 53 | * @param tokenId The ID of the token to transfer the ERC-20 tokens from 54 | * @param amount The number of ERC-20 tokens to transfer 55 | * @param data Additional data with no specified format, to allow for custom logic 56 | */ 57 | function transferHeldERC20FromToken( 58 | address erc20Contract, 59 | uint256 tokenId, 60 | address to, 61 | uint256 amount, 62 | bytes memory data 63 | ) external; 64 | 65 | /** 66 | * @notice Transfer ERC-20 tokens to a specific token. 67 | * @dev The ERC-20 smart contract must have approval for this contract to transfer the ERC-20 tokens. 68 | * @dev The balance MUST be transferred from the `msg.sender`. 69 | * @param erc20Contract The address of the ERC-20 smart contract 70 | * @param tokenId The ID of the token to transfer ERC-20 tokens to 71 | * @param amount The number of ERC-20 tokens to transfer 72 | * @param data Additional data with no specified format, to allow for custom logic 73 | */ 74 | function transferERC20ToToken( 75 | address erc20Contract, 76 | uint256 tokenId, 77 | uint256 amount, 78 | bytes memory data 79 | ) external; 80 | 81 | /** 82 | * @notice Nonce increased every time an ERC20 token is transferred out of a token 83 | * @param tokenId The ID of the token to check the nonce for 84 | * @return The nonce of the token 85 | */ 86 | function erc20TransferOutNonce( 87 | uint256 tokenId 88 | ) external view returns (uint256); 89 | } 90 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/typedMultiAsset/IRMRKTypedMultiAsset.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | // import {IERC5773} from "../../multiasset/IERC5773.sol"; 6 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 7 | 8 | /** 9 | * @title IRMRKTypedMultiAsset 10 | * @author RMRK team 11 | * @notice Interface smart contract of the RMRK typed multi asset module. 12 | */ 13 | interface IRMRKTypedMultiAsset is IERC165 { 14 | /** 15 | * @notice Used to get the type of the asset. 16 | * @param assetId ID of the asset to check 17 | * @return The type of the asset 18 | */ 19 | function getAssetType(uint64 assetId) external view returns (string memory); 20 | } 21 | -------------------------------------------------------------------------------- /contracts/RMRK/extension/typedMultiAsset/RMRKTypedMultiAsset.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {IRMRKTypedMultiAsset} from "./IRMRKTypedMultiAsset.sol"; 7 | 8 | /** 9 | * @title RMRKTypedMultiAsset 10 | * @author RMRK team 11 | * @notice Smart contract of the RMRK Typed multi asset module. 12 | */ 13 | abstract contract RMRKTypedMultiAsset is IRMRKTypedMultiAsset { 14 | mapping(uint64 => string) private _assetTypes; 15 | 16 | /** 17 | * @inheritdoc IERC165 18 | */ 19 | function supportsInterface( 20 | bytes4 interfaceId 21 | ) public view virtual returns (bool) { 22 | return interfaceId == type(IRMRKTypedMultiAsset).interfaceId; 23 | } 24 | 25 | /** 26 | * @inheritdoc IRMRKTypedMultiAsset 27 | */ 28 | function getAssetType(uint64 assetId) public view returns (string memory) { 29 | return _assetTypes[assetId]; 30 | } 31 | 32 | /** 33 | * @notice Used to set the type of the asset. 34 | * @param assetId ID of the asset for which the type is being set 35 | * @param type_ The type of the asset 36 | */ 37 | function _setAssetType(uint64 assetId, string memory type_) internal { 38 | _assetTypes[assetId] = type_; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/RMRK/library/RMRKLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title RMRKLib 7 | * @author RMRK team 8 | * @notice RMRK library smart contract. 9 | */ 10 | library RMRKLib { 11 | error IndexOutOfBounds(); 12 | 13 | /** 14 | * @notice Used to remove an item from the array using the specified index. 15 | * @dev The item is removed by replacing it with the last item and removing the last element. 16 | * @param array An array of items containing the item to be removed 17 | * @param index Index of the item to remove 18 | */ 19 | function removeItemByIndex(uint64[] storage array, uint256 index) internal { 20 | //Check to see if this is already gated by require in all calls 21 | if (index >= array.length) revert IndexOutOfBounds(); 22 | array[index] = array[array.length - 1]; 23 | array.pop(); 24 | } 25 | 26 | /** 27 | * @notice Used to determine the index of the item in the array by spedifying its value. 28 | * @dev This was adapted from Cryptofin-Solidity `arrayUtils`. 29 | * @dev If the item is not found the index returned will equal `0`. 30 | * @param A The array containing the item to be found 31 | * @param a The value of the item to find the index of 32 | * @return The index of the item in the array 33 | * @return A boolean value specifying whether the item was found 34 | */ 35 | function indexOf( 36 | uint64[] memory A, 37 | uint64 a 38 | ) internal pure returns (uint256, bool) { 39 | uint256 length = A.length; 40 | for (uint256 i; i < length; ) { 41 | if (A[i] == a) { 42 | return (i, true); 43 | } 44 | unchecked { 45 | ++i; 46 | } 47 | } 48 | return (0, false); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/RMRK/security/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) 3 | 4 | pragma solidity ^0.8.21; 5 | 6 | error RentrantCall(); 7 | 8 | /** 9 | * @title ReentrancyGuard 10 | * @notice Smart contract used to guard against potential reentrancy exploits. 11 | * @dev Contract module that helps prevent reentrant calls to a function. 12 | * 13 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 14 | * available, which can be applied to functions to make sure there are no nested 15 | * (reentrant) calls to them. 16 | * 17 | * Note that because there is a single `nonReentrant` guard, functions marked as 18 | * `nonReentrant` may not call one another. This can be worked around by making 19 | * those functions `private`, and then adding `external` `nonReentrant` entry 20 | * points to them. 21 | * 22 | * TIP: If you would like to learn more about reentrancy and alternative ways 23 | * to protect against it, check out our blog post 24 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 25 | */ 26 | abstract contract ReentrancyGuard { 27 | // Booleans are more expensive than uint256 or any type that takes up a full 28 | // word because each write operation emits an extra SLOAD to first read the 29 | // slot's contents, replace the bits taken up by the boolean, and then write 30 | // back. This is the compiler's defense against contract upgrades and 31 | // pointer aliasing, and it cannot be disabled. 32 | 33 | // The values being non-zero value makes deployment a bit more expensive, 34 | // but in exchange the refund on every call to nonReentrant will be lower in 35 | // amount. Since refunds are capped to a percentage of the total 36 | // transaction's gas, it is best to keep them low in cases like this one, to 37 | // increase the likelihood of the full refund coming into effect. 38 | uint256 private constant _NOT_ENTERED = 1; 39 | uint256 private constant _ENTERED = 2; 40 | 41 | uint256 private _status; 42 | 43 | /** 44 | * @notice Initializes the ReentrancyGuard with the `_status` of `_NOT_ENTERED`. 45 | */ 46 | constructor() { 47 | _status = _NOT_ENTERED; 48 | } 49 | 50 | /** 51 | * @notice Used to ensure that the function it is applied to cannot be reentered. 52 | * @dev Prevents a contract from calling itself, directly or indirectly. 53 | * Calling a `nonReentrant` function from another `nonReentrant` 54 | * function is not supported. It is possible to prevent this from happening 55 | * by making the `nonReentrant` function external, and making it call a 56 | * `private` function that does the actual work. 57 | */ 58 | modifier nonReentrant() { 59 | _nonReentrantIn(); 60 | _; 61 | // By storing the original value once again, a refund is triggered (see 62 | // https://eips.ethereum.org/EIPS/eip-2200) 63 | _status = _NOT_ENTERED; 64 | } 65 | 66 | /** 67 | * @notice Used to ensure that the current call is not a reentrant call. 68 | * @dev If reentrant call is detected, the execution will be reverted. 69 | */ 70 | function _nonReentrantIn() private { 71 | // On the first call to nonReentrant, _notEntered will be true 72 | if (_status == _ENTERED) revert RentrantCall(); 73 | 74 | // Any calls to nonReentrant after this point will fail 75 | _status = _ENTERED; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/RMRK/utils/IERC20.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: Apache 2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title IERC20 7 | * @notice Interface smart contract of the ERC20 smart contract implementation. 8 | */ 9 | interface IERC20 { 10 | /** 11 | * @notice Used to transfer tokens from the caller's account to another. 12 | * @param to Address of the account to which the tokens are being transferred 13 | * @param amount Amount of tokens that are being transferred 14 | * @return success A boolean value signifying whether the transfer was succesful (`true`) or not (`false`) 15 | */ 16 | function transfer( 17 | address to, 18 | uint256 amount 19 | ) external returns (bool success); 20 | 21 | /** 22 | * @notice Used to transfer tokens from one address to another. 23 | * @param from Address of the account from which the the tokens are being transferred 24 | * @param to Address of the account to which the tokens are being transferred 25 | * @param amount Amount of tokens that are being transferred 26 | * @return success A boolean value signifying whether the transfer was succesful (`true`) or not (`false`) 27 | */ 28 | function transferFrom( 29 | address from, 30 | address to, 31 | uint256 amount 32 | ) external returns (bool success); 33 | 34 | /** 35 | * @notice Used to grant permission to an account to spend the tokens of another 36 | * @param owner Address that owns the tokens 37 | * @param spender Address that is being granted the permission to spend the tokens of the `owner` 38 | * @return Amount of tokens that the `spender` can manage 39 | */ 40 | function allowance( 41 | address owner, 42 | address spender 43 | ) external view returns (uint256); 44 | } 45 | -------------------------------------------------------------------------------- /contracts/RMRK/utils/IRMRKCollectionData.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: Apache 2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | interface IRMRKCollectionData { 6 | function totalSupply() external view returns (uint256); 7 | 8 | function maxSupply() external view returns (uint256); 9 | 10 | function getRoyaltyPercentage() external view returns (uint256); 11 | 12 | function getRoyaltyRecipient() external view returns (address); 13 | 14 | function owner() external view returns (address); 15 | 16 | function name() external view returns (string memory); 17 | 18 | function symbol() external view returns (string memory); 19 | 20 | function collectionMetadata() external view returns (string memory); 21 | 22 | function contractURI() external view returns (string memory); 23 | } 24 | -------------------------------------------------------------------------------- /contracts/implementations/abstract/RMRKAbstractNestable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol"; 7 | import { 8 | IERC721Metadata 9 | } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; 10 | import {RMRKNestable} from "../../RMRK/nestable/RMRKNestable.sol"; 11 | import {RMRKImplementationBase} from "../utils/RMRKImplementationBase.sol"; 12 | 13 | /** 14 | * @title RMRKAbstractNestable 15 | * @author RMRK team 16 | * @notice Abstract implementation of RMRK nestable module. 17 | */ 18 | abstract contract RMRKAbstractNestable is RMRKImplementationBase, RMRKNestable { 19 | /** 20 | * @inheritdoc IERC165 21 | */ 22 | function supportsInterface( 23 | bytes4 interfaceId 24 | ) public view virtual override returns (bool) { 25 | return 26 | super.supportsInterface(interfaceId) || 27 | interfaceId == type(IERC2981).interfaceId || 28 | interfaceId == type(IERC721Metadata).interfaceId || 29 | interfaceId == RMRK_INTERFACE(); 30 | } 31 | 32 | function _beforeTokenTransfer( 33 | address from, 34 | address to, 35 | uint256 tokenId 36 | ) internal virtual override { 37 | super._beforeTokenTransfer(from, to, tokenId); 38 | if (to == address(0)) { 39 | unchecked { 40 | _totalSupply -= 1; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /contracts/implementations/catalog/IRMRKCatalogExtended.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IRMRKCatalog} from "../../RMRK/catalog/IRMRKCatalog.sol"; 6 | 7 | /** 8 | * @title IRMRKCatalogExtended 9 | * @author RMRK team 10 | * @notice An extended interface for Catalog for RMRK equippable module. 11 | */ 12 | interface IRMRKCatalogExtended is IRMRKCatalog { 13 | /** 14 | * @notice From ERC7572 (Draft) Emitted when the contract-level metadata is updated 15 | */ 16 | event ContractURIUpdated(); 17 | 18 | /** 19 | * @notice Emited when the type of the catalog is updated 20 | * @param newType The new type of the catalog 21 | */ 22 | event TypeUpdated(string newType); 23 | 24 | /** 25 | * @notice Used to get all the part IDs in the catalog. 26 | * @dev Can get at least 10k parts. Higher limits were not tested. 27 | * @dev It may fail if there are too many parts, in that case use either `getPaginatedPartIds` or `getTotalParts` and `getPartByIndex`. 28 | * @return partIds An array of all the part IDs in the catalog 29 | */ 30 | function getAllPartIds() external view returns (uint64[] memory partIds); 31 | 32 | /** 33 | * @notice Used to get all the part IDs in the catalog. 34 | * @param offset The offset to start from 35 | * @param limit The maximum number of parts to return 36 | * @return partIds An array of all the part IDs in the catalog 37 | */ 38 | function getPaginatedPartIds( 39 | uint256 offset, 40 | uint256 limit 41 | ) external view returns (uint64[] memory partIds); 42 | 43 | /** 44 | * @notice Used to get the total number of parts in the catalog. 45 | * @return totalParts The total number of parts in the catalog 46 | */ 47 | function getTotalParts() external view returns (uint256 totalParts); 48 | 49 | /** 50 | * @notice Used to get a single `Part` by the index of its `partId`. 51 | * @param index The index of the `partId`. 52 | * @return part The `Part` struct associated with the `partId` at the given index 53 | */ 54 | function getPartByIndex( 55 | uint256 index 56 | ) external view returns (Part memory part); 57 | 58 | /** 59 | * @notice Used to set the metadata URI of the catalog. 60 | * @param newContractURI The new metadata URI 61 | * @dev emits `ContractURIUpdated` event 62 | */ 63 | function setMetadataURI(string memory newContractURI) external; 64 | 65 | /** 66 | * @notice Used to set the type of the catalog. 67 | * @param newType The new type of the catalog 68 | * @dev emits `TypeUpdated` event 69 | */ 70 | function setType(string memory newType) external; 71 | } 72 | -------------------------------------------------------------------------------- /contracts/implementations/catalog/RMRKCatalogFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKCatalogImpl} from "./RMRKCatalogImpl.sol"; 6 | 7 | /** 8 | * @title RMRKCatalogFactory 9 | * @author RMRK team 10 | * @notice Smart contract to deploy catalog implementations and keep track of deployers. 11 | */ 12 | contract RMRKCatalogFactory { 13 | mapping(address deployer => address[] catalogs) private _deployerCatalogs; 14 | 15 | event CatalogDeployed(address indexed deployer, address indexed catalog); 16 | 17 | /** 18 | * @notice Used to deploy a new RMRKCatalog implementation. 19 | * @param metadataURI Base metadata URI of the catalog 20 | * @param type_ The type of the catalog 21 | * @return The address of the deployed catalog 22 | */ 23 | function deployCatalog( 24 | string memory metadataURI, 25 | string memory type_ 26 | ) public returns (address) { 27 | RMRKCatalogImpl catalog = new RMRKCatalogImpl(metadataURI, type_); 28 | _deployerCatalogs[msg.sender].push(address(catalog)); 29 | emit CatalogDeployed(msg.sender, address(catalog)); 30 | return address(catalog); 31 | } 32 | 33 | /** 34 | * @notice Used to get all catalogs deployed by a given deployer. 35 | * @param deployer The address of the deployer 36 | * @return An array of addresses of the catalogs deployed by the deployer 37 | */ 38 | function getDeployerCatalogs( 39 | address deployer 40 | ) public view returns (address[] memory) { 41 | return _deployerCatalogs[deployer]; 42 | } 43 | 44 | /** 45 | * @notice Used to get the total number of catalogs deployed by a given deployer. 46 | * @param deployer The address of the deployer 47 | * @return total The total number of catalogs deployed by the deployer 48 | */ 49 | function getTotalDeployerCatalogs( 50 | address deployer 51 | ) public view returns (uint256 total) { 52 | total = _deployerCatalogs[deployer].length; 53 | } 54 | 55 | /** 56 | * @notice Used to get a catalog deployed by a given deployer at a given index. 57 | * @param deployer The address of the deployer 58 | * @param index The index of the catalog 59 | * @return catalogAddress The address of the catalog 60 | */ 61 | function getDeployerCatalogAtIndex( 62 | address deployer, 63 | uint256 index 64 | ) public view returns (address catalogAddress) { 65 | catalogAddress = _deployerCatalogs[deployer][index]; 66 | } 67 | 68 | /** 69 | * @notice Used to get the last catalog deployed by a given deployer. 70 | * @param deployer The address of the deployer 71 | * @return catalogAddress The address of the last catalog deployed by the deployer 72 | */ 73 | function getLastDeployerCatalog( 74 | address deployer 75 | ) public view returns (address catalogAddress) { 76 | catalogAddress = _deployerCatalogs[deployer][ 77 | _deployerCatalogs[deployer].length - 1 78 | ]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintErc20/InitDataERC20Pay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title InitDataERC20Pay 7 | * @author RMRK team 8 | * @notice Interface representation of RMRK initialization data. 9 | * @dev This interface provides a struct used to pack data to avoid stack too deep error for too many arguments. 10 | */ 11 | interface InitDataERC20Pay { 12 | /** 13 | * @notice Used to provide initialization data without running into stack too deep errors. 14 | * @return erc20TokenAddress Address of the ERC20 token to be used when initializing a smart contract that supports 15 | * ERC20 pay module 16 | * @return royaltyRecipient Recipient of resale royalties 17 | * @return royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 18 | * @return maxSupply The maximum supply of tokens 19 | * @return pricePerMint The price per single-token mint expressed in the lowest denomination of native currency 20 | */ 21 | struct InitData { 22 | address erc20TokenAddress; // 20 bytes 23 | // --- new slot --- 24 | address royaltyRecipient; // 20 bytes 25 | uint16 royaltyPercentageBps; // 2 bytes 26 | // --- new slot --- 27 | uint256 maxSupply; 28 | // --- new slot --- 29 | uint256 pricePerMint; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintErc20/RMRKEquippableLazyMintErc20Soulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKEquippableLazyMintErc20} from "./RMRKEquippableLazyMintErc20.sol"; 7 | import {RMRKAbstractEquippable} from "../abstract/RMRKAbstractEquippable.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKEquippableLazyMintErc20Soulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK equippable module with ERC20-powered lazy minting. 14 | */ 15 | contract RMRKEquippableLazyMintErc20Soulbound is 16 | RMRKSoulbound, 17 | RMRKEquippableLazyMintErc20 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata URI to the collection's metadata 24 | * @param baseTokenURI The base URI of the token metadata 25 | * @param data The `InitData` struct used to pass the initialization parameters. 26 | */ 27 | constructor( 28 | string memory name, 29 | string memory symbol, 30 | string memory collectionMetadata, 31 | string memory baseTokenURI, 32 | InitData memory data 33 | ) 34 | RMRKEquippableLazyMintErc20( 35 | name, 36 | symbol, 37 | collectionMetadata, 38 | baseTokenURI, 39 | data 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractEquippable) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractEquippable.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractEquippable) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractEquippable._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintErc20/RMRKMultiAssetLazyMintErc20Soulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractMultiAsset} from "../abstract/RMRKAbstractMultiAsset.sol"; 7 | import {RMRKMultiAssetLazyMintErc20} from "./RMRKMultiAssetLazyMintErc20.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKMultiAssetLazyMintErc20Soulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK multi-asset module with ERC20-powered lazy minting. 14 | */ 15 | contract RMRKMultiAssetLazyMintErc20Soulbound is 16 | RMRKSoulbound, 17 | RMRKMultiAssetLazyMintErc20 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata URI to the collection's metadata 24 | * @param baseTokenURI Each token's base URI 25 | * @param data The `InitData` struct used to pass initialization parameters 26 | */ 27 | constructor( 28 | string memory name, 29 | string memory symbol, 30 | string memory collectionMetadata, 31 | string memory baseTokenURI, 32 | InitData memory data 33 | ) 34 | RMRKMultiAssetLazyMintErc20( 35 | name, 36 | symbol, 37 | collectionMetadata, 38 | baseTokenURI, 39 | data 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractMultiAsset) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractMultiAsset.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractMultiAsset) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractMultiAsset._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintErc20/RMRKNestableLazyMintErc20Soulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractNestable} from "../abstract/RMRKAbstractNestable.sol"; 7 | import {RMRKNestableLazyMintErc20} from "./RMRKNestableLazyMintErc20.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKNestableLazyMintErc20Soulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK nestable module with ERC20-powered lazy minting. 14 | */ 15 | contract RMRKNestableLazyMintErc20Soulbound is 16 | RMRKSoulbound, 17 | RMRKNestableLazyMintErc20 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata URI to the collection's metadata 24 | * @param baseTokenURI Each token's base URI 25 | * @param data The `InitData` struct used to pass initialization parameters 26 | */ 27 | constructor( 28 | string memory name, 29 | string memory symbol, 30 | string memory collectionMetadata, 31 | string memory baseTokenURI, 32 | InitData memory data 33 | ) 34 | RMRKNestableLazyMintErc20( 35 | name, 36 | symbol, 37 | collectionMetadata, 38 | baseTokenURI, 39 | data 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractNestable) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractNestable.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestable) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractNestable._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintErc20/RMRKNestableMultiAssetLazyMintErc20Soulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import { 7 | RMRKAbstractNestableMultiAsset 8 | } from "../abstract/RMRKAbstractNestableMultiAsset.sol"; 9 | import { 10 | RMRKNestableMultiAssetLazyMintErc20 11 | } from "./RMRKNestableMultiAssetLazyMintErc20.sol"; 12 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 13 | 14 | /** 15 | * @title RMRKNestableMultiAssetLazyMintErc20Soulbound 16 | * @author RMRK team 17 | * @notice Implementation of joined non-transferable RMRK nestable and multi asset module with ERC20-powered lazy minting. 18 | */ 19 | contract RMRKNestableMultiAssetLazyMintErc20Soulbound is 20 | RMRKSoulbound, 21 | RMRKNestableMultiAssetLazyMintErc20 22 | { 23 | /** 24 | * @notice Used to initialize the smart contract. 25 | * @param name Name of the token collection 26 | * @param symbol Symbol of the token collection 27 | * @param collectionMetadata URI to the collection's metadata 28 | * @param baseTokenURI Each token's base URI 29 | * @param data The `InitData` struct used to pass initialization parameters 30 | */ 31 | constructor( 32 | string memory name, 33 | string memory symbol, 34 | string memory collectionMetadata, 35 | string memory baseTokenURI, 36 | InitData memory data 37 | ) 38 | RMRKNestableMultiAssetLazyMintErc20( 39 | name, 40 | symbol, 41 | collectionMetadata, 42 | baseTokenURI, 43 | data 44 | ) 45 | {} 46 | 47 | /** 48 | * @inheritdoc IERC165 49 | */ 50 | function supportsInterface( 51 | bytes4 interfaceId 52 | ) 53 | public 54 | view 55 | virtual 56 | override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) 57 | returns (bool) 58 | { 59 | return 60 | RMRKAbstractNestableMultiAsset.supportsInterface(interfaceId) || 61 | RMRKSoulbound.supportsInterface(interfaceId); 62 | } 63 | 64 | function _beforeTokenTransfer( 65 | address from, 66 | address to, 67 | uint256 tokenId 68 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) { 69 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 70 | RMRKAbstractNestableMultiAsset._beforeTokenTransfer(from, to, tokenId); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/InitDataNativePay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title InitDataNativePay 7 | * @author RMRK team 8 | * @notice Interface representation of RMRK initialization data. 9 | * @dev This interface provides a struct used to pack data to avoid stack too deep error for too many arguments. 10 | */ 11 | interface InitDataNativePay { 12 | /** 13 | * @notice Used to provide initialization data without running into stack too deep errors. 14 | * @return royaltyRecipient Recipient of resale royalties 15 | * @return royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 16 | * @return maxSupply The maximum supply of tokens 17 | * @return pricePerMint The price per single-token mint expressed in the lowest denomination of native currency 18 | */ 19 | struct InitData { 20 | address royaltyRecipient; // 20 bytes 21 | uint16 royaltyPercentageBps; // 2 bytes 22 | // --- new slot --- 23 | uint256 maxSupply; 24 | // --- new slot --- 25 | uint256 pricePerMint; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/RMRKEquippableLazyMintNativeSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractEquippable} from "../abstract/RMRKAbstractEquippable.sol"; 7 | import {RMRKEquippableLazyMintNative} from "./RMRKEquippableLazyMintNative.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKEquippableLazyMintNativeSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK equippable module with native token-powered lazy minting. 14 | */ 15 | contract RMRKEquippableLazyMintNativeSoulbound is 16 | RMRKSoulbound, 17 | RMRKEquippableLazyMintNative 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata URI to the collection's metadata 24 | * @param baseTokenURI Each token's base URI 25 | * @param data The `InitData` struct used to pass initialization parameters 26 | */ 27 | constructor( 28 | string memory name, 29 | string memory symbol, 30 | string memory collectionMetadata, 31 | string memory baseTokenURI, 32 | InitData memory data 33 | ) 34 | RMRKEquippableLazyMintNative( 35 | name, 36 | symbol, 37 | collectionMetadata, 38 | baseTokenURI, 39 | data 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractEquippable) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractEquippable.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractEquippable) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractEquippable._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/RMRKMultiAssetLazyMintNative.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKAbstractMultiAsset} from "../abstract/RMRKAbstractMultiAsset.sol"; 6 | import {RMRKImplementationBase} from "../utils/RMRKImplementationBase.sol"; 7 | import {RMRKTokenURIEnumerated} from "../utils/RMRKTokenURIEnumerated.sol"; 8 | import {InitDataNativePay} from "./InitDataNativePay.sol"; 9 | import "../../RMRK/library/RMRKErrors.sol"; 10 | 11 | /** 12 | * @title RMRKMultiAssetLazyMintNative 13 | * @author RMRK team 14 | * @notice Implementation of RMRK multi asset module with native token-powered lazy minting. 15 | */ 16 | contract RMRKMultiAssetLazyMintNative is 17 | InitDataNativePay, 18 | RMRKTokenURIEnumerated, 19 | RMRKAbstractMultiAsset 20 | { 21 | uint256 private _pricePerMint; 22 | 23 | /** 24 | * @notice Used to initialize the smart contract. 25 | * @param name Name of the token collection 26 | * @param symbol Symbol of the token collection 27 | * @param collectionMetadata URI to the collection's metadata 28 | * @param baseTokenURI Each token's base URI 29 | * @param data The `InitData` struct used to pass initialization parameters 30 | */ 31 | constructor( 32 | string memory name, 33 | string memory symbol, 34 | string memory collectionMetadata, 35 | string memory baseTokenURI, 36 | InitData memory data 37 | ) 38 | RMRKTokenURIEnumerated(baseTokenURI) 39 | RMRKImplementationBase( 40 | name, 41 | symbol, 42 | collectionMetadata, 43 | data.maxSupply, 44 | data.royaltyRecipient, 45 | data.royaltyPercentageBps 46 | ) 47 | { 48 | _pricePerMint = data.pricePerMint; 49 | } 50 | 51 | /** 52 | * @notice Used to mint the desired number of tokens to the specified address. 53 | * @dev The `data` value of the `_safeMint` method is set to an empty value. 54 | * @dev Can only be called while the open sale is open. 55 | * @param to Address to which to mint the token 56 | * @param numToMint Number of tokens to mint 57 | * @return firstTokenId The ID of the first token to be minted in the current minting cycle 58 | */ 59 | function mint( 60 | address to, 61 | uint256 numToMint 62 | ) public payable virtual returns (uint256 firstTokenId) { 63 | (uint256 nextToken, uint256 totalSupplyOffset) = _prepareMint( 64 | numToMint 65 | ); 66 | _chargeMints(numToMint); 67 | 68 | for (uint256 i = nextToken; i < totalSupplyOffset; ) { 69 | _safeMint(to, i, ""); 70 | unchecked { 71 | ++i; 72 | } 73 | } 74 | 75 | firstTokenId = nextToken; 76 | } 77 | 78 | function _chargeMints(uint256 numToMint) internal { 79 | uint256 price = numToMint * _pricePerMint; 80 | if (price != msg.value) revert RMRKWrongValueSent(); 81 | } 82 | 83 | /** 84 | * @notice Used to retrieve the price per mint. 85 | * @return price The price per mint of a single token expressed in the lowest denomination of a native currency 86 | */ 87 | function pricePerMint() public view returns (uint256 price) { 88 | price = _pricePerMint; 89 | } 90 | 91 | /** 92 | * @notice Used to withdraw the minting proceedings to a specified address. 93 | * @dev This function can only be called by the owner. 94 | * @param to Address to receive the given amount of minting proceedings 95 | * @param amount The amount to withdraw 96 | */ 97 | function withdraw(address to, uint256 amount) external onlyOwner { 98 | (bool success, ) = to.call{value: amount}(""); 99 | if (!success) revert TransferFailed(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/RMRKMultiAssetLazyMintNativeSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractMultiAsset} from "../abstract/RMRKAbstractMultiAsset.sol"; 7 | import {RMRKMultiAssetLazyMintNative} from "./RMRKMultiAssetLazyMintNative.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKMultiAssetLazyMintNativeSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK multi asset module with native token-powered lazy minting. 14 | */ 15 | contract RMRKMultiAssetLazyMintNativeSoulbound is 16 | RMRKSoulbound, 17 | RMRKMultiAssetLazyMintNative 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata URI to the collection's metadata 24 | * @param baseTokenURI Each token's base URI 25 | * @param data The `InitData` struct used to pass initialization parameters 26 | */ 27 | constructor( 28 | string memory name, 29 | string memory symbol, 30 | string memory collectionMetadata, 31 | string memory baseTokenURI, 32 | InitData memory data 33 | ) 34 | RMRKMultiAssetLazyMintNative( 35 | name, 36 | symbol, 37 | collectionMetadata, 38 | baseTokenURI, 39 | data 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractMultiAsset) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractMultiAsset.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractMultiAsset) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractMultiAsset._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/RMRKNestableLazyMintNativeSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractNestable} from "../abstract/RMRKAbstractNestable.sol"; 7 | import {RMRKNestableLazyMintNative} from "./RMRKNestableLazyMintNative.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKNestableLazyMintNativeSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK nestable module with native token-powered lazy minting. 14 | */ 15 | /** 16 | * @title RMRKNestableLazyMintNativeSoulbound 17 | * @author RMRK team 18 | * @notice Implementation of non-transferable RMRK nestable module with native token-powered lazy minting. 19 | */ 20 | contract RMRKNestableLazyMintNativeSoulbound is 21 | RMRKSoulbound, 22 | RMRKNestableLazyMintNative 23 | { 24 | /** 25 | * @notice Used to initialize the smart contract. 26 | * @param name Name of the token collection 27 | * @param symbol Symbol of the token collection 28 | * @param collectionMetadata URI to the collection's metadata 29 | * @param baseTokenURI Each token's base URI 30 | * @param data The `InitData` struct used to pass initialization parameters 31 | */ 32 | /** 33 | * @notice Used to initialize the smart contract. 34 | * @param name Name of the token collection 35 | * @param symbol Symbol of the token collection 36 | * @param collectionMetadata URI to the collection's metadata 37 | * @param baseTokenURI Each token's base URI 38 | * @param data The `InitData` struct used to pass initialization parameters 39 | */ 40 | constructor( 41 | string memory name, 42 | string memory symbol, 43 | string memory collectionMetadata, 44 | string memory baseTokenURI, 45 | InitData memory data 46 | ) 47 | RMRKNestableLazyMintNative( 48 | name, 49 | symbol, 50 | collectionMetadata, 51 | baseTokenURI, 52 | data 53 | ) 54 | {} 55 | 56 | /** 57 | * @inheritdoc IERC165 58 | */ 59 | function supportsInterface( 60 | bytes4 interfaceId 61 | ) 62 | public 63 | view 64 | virtual 65 | override(RMRKSoulbound, RMRKAbstractNestable) 66 | returns (bool) 67 | { 68 | return 69 | RMRKAbstractNestable.supportsInterface(interfaceId) || 70 | RMRKSoulbound.supportsInterface(interfaceId); 71 | } 72 | 73 | function _beforeTokenTransfer( 74 | address from, 75 | address to, 76 | uint256 tokenId 77 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestable) { 78 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 79 | RMRKAbstractNestable._beforeTokenTransfer(from, to, tokenId); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /contracts/implementations/lazyMintNative/RMRKNestableMultiAssetLazyMintNativeSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import { 7 | RMRKAbstractNestableMultiAsset 8 | } from "../abstract/RMRKAbstractNestableMultiAsset.sol"; 9 | import { 10 | RMRKNestableMultiAssetLazyMintNative 11 | } from "./RMRKNestableMultiAssetLazyMintNative.sol"; 12 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 13 | 14 | /** 15 | * @title RMRKNestableMultiAssetLazyMintNativeSoulbound 16 | * @author RMRK team 17 | * @notice Implementation of joined non-transferable RMRK nestable and multi asset modules with native token-powered lazy minting. 18 | */ 19 | /** 20 | * @title RMRKNestableMultiAssetLazyMintNativeSoulbound 21 | * @author RMRK team 22 | * @notice Implementation of joined non-transferable RMRK nestable and multi asset modules with native token-powered lazy minting. 23 | */ 24 | contract RMRKNestableMultiAssetLazyMintNativeSoulbound is 25 | RMRKSoulbound, 26 | RMRKNestableMultiAssetLazyMintNative 27 | { 28 | /** 29 | * @notice Used to initialize the smart contract. 30 | * @param name Name of the token collection 31 | * @param symbol Symbol of the token collection 32 | * @param collectionMetadata URI to the collection's metadata 33 | * @param baseTokenURI Each token's base URI 34 | * @param data The `InitData` struct used to pass initialization parameters 35 | */ 36 | /** 37 | * @notice Used to initialize the smart contract. 38 | * @param name Name of the token collection 39 | * @param symbol Symbol of the token collection 40 | * @param collectionMetadata URI to the collection's metadata 41 | * @param baseTokenURI Each token's base URI 42 | * @param data The `InitData` struct used to pass initialization parameters 43 | */ 44 | constructor( 45 | string memory name, 46 | string memory symbol, 47 | string memory collectionMetadata, 48 | string memory baseTokenURI, 49 | InitData memory data 50 | ) 51 | RMRKNestableMultiAssetLazyMintNative( 52 | name, 53 | symbol, 54 | collectionMetadata, 55 | baseTokenURI, 56 | data 57 | ) 58 | {} 59 | 60 | /** 61 | * @inheritdoc IERC165 62 | */ 63 | function supportsInterface( 64 | bytes4 interfaceId 65 | ) 66 | public 67 | view 68 | virtual 69 | override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) 70 | returns (bool) 71 | { 72 | return 73 | RMRKAbstractNestableMultiAsset.supportsInterface(interfaceId) || 74 | RMRKSoulbound.supportsInterface(interfaceId); 75 | } 76 | 77 | function _beforeTokenTransfer( 78 | address from, 79 | address to, 80 | uint256 tokenId 81 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) { 82 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 83 | RMRKAbstractNestableMultiAsset._beforeTokenTransfer(from, to, tokenId); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /contracts/implementations/premint/RMRKEquippablePreMintSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractEquippable} from "../abstract/RMRKAbstractEquippable.sol"; 7 | import {RMRKEquippablePreMint} from "./RMRKEquippablePreMint.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKEquippablePreMintSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK equippable module with pre-minting. 14 | */ 15 | contract RMRKEquippablePreMintSoulbound is 16 | RMRKSoulbound, 17 | RMRKEquippablePreMint 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata CID of the collection metadata 24 | * @param maxSupply The maximum supply of tokens 25 | * @param royaltyRecipient Recipient of resale royalties 26 | * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 27 | */ 28 | constructor( 29 | string memory name, 30 | string memory symbol, 31 | string memory collectionMetadata, 32 | uint256 maxSupply, 33 | address royaltyRecipient, 34 | uint16 royaltyPercentageBps 35 | ) 36 | RMRKEquippablePreMint( 37 | name, 38 | symbol, 39 | collectionMetadata, 40 | maxSupply, 41 | royaltyRecipient, 42 | royaltyPercentageBps 43 | ) 44 | {} 45 | 46 | /** 47 | * @inheritdoc IERC165 48 | */ 49 | function supportsInterface( 50 | bytes4 interfaceId 51 | ) 52 | public 53 | view 54 | virtual 55 | override(RMRKSoulbound, RMRKAbstractEquippable) 56 | returns (bool) 57 | { 58 | return 59 | RMRKAbstractEquippable.supportsInterface(interfaceId) || 60 | RMRKSoulbound.supportsInterface(interfaceId); 61 | } 62 | 63 | function _beforeTokenTransfer( 64 | address from, 65 | address to, 66 | uint256 tokenId 67 | ) internal virtual override(RMRKSoulbound, RMRKAbstractEquippable) { 68 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 69 | RMRKAbstractEquippable._beforeTokenTransfer(from, to, tokenId); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /contracts/implementations/premint/RMRKMultiAssetPreMint.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKAbstractMultiAsset} from "../abstract/RMRKAbstractMultiAsset.sol"; 6 | import {RMRKImplementationBase} from "../utils/RMRKImplementationBase.sol"; 7 | import {RMRKTokenURIPerToken} from "../utils/RMRKTokenURIPerToken.sol"; 8 | 9 | /** 10 | * @title RMRKMultiAssetPreMint 11 | * @author RMRK team 12 | * @notice Implementation of RMRK multi asset module with pre-minting. 13 | */ 14 | contract RMRKMultiAssetPreMint is RMRKTokenURIPerToken, RMRKAbstractMultiAsset { 15 | /** 16 | * @notice Used to initialize the smart contract. 17 | * @param name Name of the token collection 18 | * @param symbol Symbol of the token collection 19 | * @param collectionMetadata CID of the collection metadata 20 | * @param maxSupply The maximum supply of tokens 21 | * @param royaltyRecipient Recipient of resale royalties 22 | * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 23 | */ 24 | constructor( 25 | string memory name, 26 | string memory symbol, 27 | string memory collectionMetadata, 28 | uint256 maxSupply, 29 | address royaltyRecipient, 30 | uint16 royaltyPercentageBps 31 | ) 32 | RMRKImplementationBase( 33 | name, 34 | symbol, 35 | collectionMetadata, 36 | maxSupply, 37 | royaltyRecipient, 38 | royaltyPercentageBps 39 | ) 40 | {} 41 | 42 | /** 43 | * @notice Used to mint the desired number of tokens to the specified address. 44 | * @dev The `data` value of the `_safeMint` method is set to an empty value. 45 | * @dev Can only be called while the open sale is open. 46 | * @param to Address to which to mint the token 47 | * @param numToMint Number of tokens to mint 48 | * @param tokenURI URI assigned to all the minted tokens 49 | * @return firstTokenId The ID of the first token to be minted in the current minting cycle 50 | */ 51 | function mint( 52 | address to, 53 | uint256 numToMint, 54 | string memory tokenURI 55 | ) public virtual onlyOwnerOrContributor returns (uint256 firstTokenId) { 56 | (uint256 nextToken, uint256 totalSupplyOffset) = _prepareMint( 57 | numToMint 58 | ); 59 | 60 | for (uint256 i = nextToken; i < totalSupplyOffset; ) { 61 | _setTokenURI(i, tokenURI); 62 | _safeMint(to, i, ""); 63 | unchecked { 64 | ++i; 65 | } 66 | } 67 | 68 | firstTokenId = nextToken; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/implementations/premint/RMRKMultiAssetPreMintSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractMultiAsset} from "../abstract/RMRKAbstractMultiAsset.sol"; 7 | import {RMRKMultiAssetPreMint} from "./RMRKMultiAssetPreMint.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKMultiAssetPreMintSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK multi asset module with pre-minting. 14 | */ 15 | contract RMRKMultiAssetPreMintSoulbound is 16 | RMRKSoulbound, 17 | RMRKMultiAssetPreMint 18 | { 19 | /** 20 | * @notice Used to initialize the smart contract. 21 | * @param name Name of the token collection 22 | * @param symbol Symbol of the token collection 23 | * @param collectionMetadata CID of the collection metadata 24 | * @param maxSupply The maximum supply of tokens 25 | * @param royaltyRecipient Recipient of resale royalties 26 | * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 27 | */ 28 | constructor( 29 | string memory name, 30 | string memory symbol, 31 | string memory collectionMetadata, 32 | uint256 maxSupply, 33 | address royaltyRecipient, 34 | uint16 royaltyPercentageBps 35 | ) 36 | RMRKMultiAssetPreMint( 37 | name, 38 | symbol, 39 | collectionMetadata, 40 | maxSupply, 41 | royaltyRecipient, 42 | royaltyPercentageBps 43 | ) 44 | {} 45 | 46 | /** 47 | * @inheritdoc IERC165 48 | */ 49 | function supportsInterface( 50 | bytes4 interfaceId 51 | ) 52 | public 53 | view 54 | virtual 55 | override(RMRKSoulbound, RMRKAbstractMultiAsset) 56 | returns (bool) 57 | { 58 | return 59 | RMRKAbstractMultiAsset.supportsInterface(interfaceId) || 60 | RMRKSoulbound.supportsInterface(interfaceId); 61 | } 62 | 63 | function _beforeTokenTransfer( 64 | address from, 65 | address to, 66 | uint256 tokenId 67 | ) internal virtual override(RMRKSoulbound, RMRKAbstractMultiAsset) { 68 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 69 | RMRKAbstractMultiAsset._beforeTokenTransfer(from, to, tokenId); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /contracts/implementations/premint/RMRKNestableMultiAssetPreMintSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import { 7 | RMRKAbstractNestableMultiAsset 8 | } from "../abstract/RMRKAbstractNestableMultiAsset.sol"; 9 | import { 10 | RMRKNestableMultiAssetPreMint 11 | } from "./RMRKNestableMultiAssetPreMint.sol"; 12 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 13 | 14 | /** 15 | * @title RMRKNestableMultiAssetPreMintSoulbound 16 | * @author RMRK team 17 | * @notice Implementation of joined non-transferable RMRK nestable and multi asset modules with pre-minting. 18 | */ 19 | contract RMRKNestableMultiAssetPreMintSoulbound is 20 | RMRKSoulbound, 21 | RMRKNestableMultiAssetPreMint 22 | { 23 | /** 24 | * @notice Used to initialize the smart contract. 25 | * @param name Name of the token collection 26 | * @param symbol Symbol of the token collection 27 | * @param collectionMetadata CID of the collection metadata 28 | * @param maxSupply The maximum supply of tokens 29 | * @param royaltyRecipient Recipient of resale royalties 30 | * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 31 | */ 32 | constructor( 33 | string memory name, 34 | string memory symbol, 35 | string memory collectionMetadata, 36 | uint256 maxSupply, 37 | address royaltyRecipient, 38 | uint16 royaltyPercentageBps 39 | ) 40 | RMRKNestableMultiAssetPreMint( 41 | name, 42 | symbol, 43 | collectionMetadata, 44 | maxSupply, 45 | royaltyRecipient, 46 | royaltyPercentageBps 47 | ) 48 | {} 49 | 50 | /** 51 | * @inheritdoc IERC165 52 | */ 53 | function supportsInterface( 54 | bytes4 interfaceId 55 | ) 56 | public 57 | view 58 | virtual 59 | override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) 60 | returns (bool) 61 | { 62 | return 63 | RMRKAbstractNestableMultiAsset.supportsInterface(interfaceId) || 64 | RMRKSoulbound.supportsInterface(interfaceId); 65 | } 66 | 67 | function _beforeTokenTransfer( 68 | address from, 69 | address to, 70 | uint256 tokenId 71 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestableMultiAsset) { 72 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 73 | RMRKAbstractNestableMultiAsset._beforeTokenTransfer(from, to, tokenId); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/implementations/premint/RMRKNestablePreMintSoulbound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 6 | import {RMRKAbstractNestable} from "../abstract/RMRKAbstractNestable.sol"; 7 | import {RMRKNestablePreMint} from "./RMRKNestablePreMint.sol"; 8 | import {RMRKSoulbound} from "../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 9 | 10 | /** 11 | * @title RMRKNestablePreMintSoulbound 12 | * @author RMRK team 13 | * @notice Implementation of non-transferable RMRK nestable module with pre-minting. 14 | */ 15 | contract RMRKNestablePreMintSoulbound is RMRKSoulbound, RMRKNestablePreMint { 16 | /** 17 | * @notice Used to initialize the smart contract. 18 | * @param name Name of the token collection 19 | * @param symbol Symbol of the token collection 20 | * @param collectionMetadata CID of the collection metadata 21 | * @param maxSupply The maximum supply of tokens 22 | * @param royaltyRecipient Recipient of resale royalties 23 | * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points 24 | */ 25 | constructor( 26 | string memory name, 27 | string memory symbol, 28 | string memory collectionMetadata, 29 | uint256 maxSupply, 30 | address royaltyRecipient, 31 | uint16 royaltyPercentageBps 32 | ) 33 | RMRKNestablePreMint( 34 | name, 35 | symbol, 36 | collectionMetadata, 37 | maxSupply, 38 | royaltyRecipient, 39 | royaltyPercentageBps 40 | ) 41 | {} 42 | 43 | /** 44 | * @inheritdoc IERC165 45 | */ 46 | function supportsInterface( 47 | bytes4 interfaceId 48 | ) 49 | public 50 | view 51 | virtual 52 | override(RMRKSoulbound, RMRKAbstractNestable) 53 | returns (bool) 54 | { 55 | return 56 | RMRKAbstractNestable.supportsInterface(interfaceId) || 57 | RMRKSoulbound.supportsInterface(interfaceId); 58 | } 59 | 60 | function _beforeTokenTransfer( 61 | address from, 62 | address to, 63 | uint256 tokenId 64 | ) internal virtual override(RMRKSoulbound, RMRKAbstractNestable) { 65 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 66 | RMRKAbstractNestable._beforeTokenTransfer(from, to, tokenId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/implementations/utils/RMRKTokenURIEnumerated.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; 6 | 7 | /** 8 | * @title RMRKTokenURIEnumerated 9 | * @author RMRK team 10 | * @notice Implementation of enumerable token URI. 11 | */ 12 | contract RMRKTokenURIEnumerated { 13 | using Strings for uint256; 14 | 15 | string private _baseTokenURI; 16 | 17 | constructor(string memory baseTokenURI) { 18 | _baseTokenURI = baseTokenURI; 19 | } 20 | 21 | /** 22 | * @notice Used to retrieve the metadata URI of a token. 23 | * @param tokenId ID of the token to retrieve the metadata URI for 24 | * @return tokenURI_ Metadata URI of the specified token 25 | */ 26 | function tokenURI( 27 | uint256 tokenId 28 | ) public view virtual returns (string memory tokenURI_) { 29 | tokenURI_ = string(abi.encodePacked(_baseTokenURI, tokenId.toString())); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /contracts/implementations/utils/RMRKTokenURIPerToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /** 6 | * @title RMRKTokenURIPerToken 7 | * @author RMRK team 8 | * @notice Implementation of token URI per token. 9 | */ 10 | contract RMRKTokenURIPerToken { 11 | mapping(uint256 => string) private _tokenURIs; 12 | 13 | /** 14 | * @notice Used to retrieve the metadata URI of a token. 15 | * @param tokenId ID of the token to retrieve the metadata URI for 16 | * @return tokenURI_ Metadata URI of the specified token 17 | */ 18 | function tokenURI( 19 | uint256 tokenId 20 | ) public view virtual returns (string memory tokenURI_) { 21 | tokenURI_ = _tokenURIs[tokenId]; 22 | } 23 | 24 | /** 25 | * @notice Used to set the token URI configuration. 26 | * @param tokenId ID of the token to set the metadata URI for 27 | * @param tokenURI_ Metadata URI to apply to all tokens, either as base or as full URI for every token 28 | */ 29 | function _setTokenURI( 30 | uint256 tokenId, 31 | string memory tokenURI_ 32 | ) internal virtual { 33 | _tokenURIs[tokenId] = tokenURI_; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/mocks/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.21; 3 | 4 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract ERC20Mock is ERC20 { 7 | constructor() ERC20("Test Token", "TEST") {} 8 | 9 | function mint(address to, uint256 amount) public { 10 | _mint(to, amount); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mocks/ERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | 7 | /** 8 | * @title ERC721Mock 9 | * Used for tests with non RMRK implementer 10 | */ 11 | contract ERC721Mock is ERC721 { 12 | constructor( 13 | string memory name, 14 | string memory symbol 15 | ) ERC721(name, symbol) {} 16 | 17 | function mint(address to, uint256 tokenId) public { 18 | _safeMint(to, tokenId); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/mocks/ERC721ReceiverMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | IERC721Receiver 7 | } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; 8 | 9 | contract ERC721ReceiverMock is IERC721Receiver { 10 | enum Error { 11 | None, 12 | RevertWithMessage, 13 | RevertWithoutMessage, 14 | Panic 15 | } 16 | 17 | bytes4 internal immutable _RET_VAL; 18 | Error internal immutable _ERROR; 19 | 20 | event Received( 21 | address indexed operator, 22 | address indexed from, 23 | uint256 indexed tokenId, 24 | bytes data 25 | ); 26 | 27 | constructor(bytes4 retval, Error error) { 28 | _RET_VAL = retval; 29 | _ERROR = error; 30 | } 31 | 32 | function onERC721Received( 33 | address operator, 34 | address from, 35 | uint256 tokenId, 36 | bytes memory data 37 | ) public override returns (bytes4) { 38 | if (_ERROR == Error.RevertWithMessage) { 39 | revert("ERC721ReceiverMock: reverting"); 40 | } else if (_ERROR == Error.RevertWithoutMessage) { 41 | revert(); 42 | } else if (_ERROR == Error.Panic) { 43 | uint256 a = uint256(0) / uint256(0); 44 | a; 45 | } 46 | emit Received(operator, from, tokenId, data); 47 | return _RET_VAL; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/mocks/OwnableLockMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {OwnableLock} from "../RMRK/access/OwnableLock.sol"; 6 | 7 | contract OwnableLockMock is OwnableLock { 8 | function testLock() external view notLocked returns (bool) { 9 | return true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mocks/OwnableMintableERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | /// @dev This mock smart contract is intended to be used with `@defi-wonderland/smock` and doesn't need any business 6 | /// logic. 7 | contract OwnableMintableERC721Mock { 8 | address private _mockOwner; 9 | address private _mockOwnerOf; 10 | 11 | constructor(address mockOwner, address mockOwnerOf) { 12 | _mockOwner = mockOwner; 13 | _mockOwnerOf = mockOwnerOf; 14 | } 15 | 16 | function owner() public view returns (address) { 17 | return _mockOwner; 18 | } 19 | 20 | function ownerOf(uint256) public view returns (address) { 21 | return _mockOwnerOf; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKEquippableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKEquippable} from "../RMRK/equippable/RMRKEquippable.sol"; 6 | 7 | //Minimal public implementation of RMRKEquippable for testing. 8 | contract RMRKEquippableMock is RMRKEquippable { 9 | function mint(address to, uint256 tokenId) external { 10 | _mint(to, tokenId, ""); 11 | } 12 | 13 | function nestMint( 14 | address to, 15 | uint256 tokenId, 16 | uint256 destinationId 17 | ) external { 18 | _nestMint(to, tokenId, destinationId, ""); 19 | } 20 | 21 | // Utility transfers: 22 | 23 | function transfer(address to, uint256 tokenId) public virtual { 24 | transferFrom(_msgSender(), to, tokenId); 25 | } 26 | 27 | function nestTransfer( 28 | address to, 29 | uint256 tokenId, 30 | uint256 destinationId 31 | ) public virtual { 32 | nestTransferFrom(_msgSender(), to, tokenId, destinationId, ""); 33 | } 34 | 35 | function addAssetToToken( 36 | uint256 tokenId, 37 | uint64 assetId, 38 | uint64 replacesAssetWithId 39 | ) external { 40 | _addAssetToToken(tokenId, assetId, replacesAssetWithId); 41 | } 42 | 43 | function addEquippableAssetEntry( 44 | uint64 id, 45 | uint64 equippableGroupId, 46 | address catalogAddress, 47 | string memory metadataURI, 48 | uint64[] calldata partIds 49 | ) external { 50 | _addAssetEntry( 51 | id, 52 | equippableGroupId, 53 | catalogAddress, 54 | metadataURI, 55 | partIds 56 | ); 57 | } 58 | 59 | function setValidParentForEquippableGroup( 60 | uint64 equippableGroupId, 61 | address parentAddress, 62 | uint64 partId 63 | ) external { 64 | _setValidParentForEquippableGroup( 65 | equippableGroupId, 66 | parentAddress, 67 | partId 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKImplementationBaseMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKImplementationBase 7 | } from "../implementations/utils/RMRKImplementationBase.sol"; 8 | 9 | contract RMRKImplementationBaseMock is RMRKImplementationBase { 10 | constructor( 11 | string memory name, 12 | string memory symbol, 13 | string memory collectionMetadata, 14 | uint256 maxSupply 15 | ) 16 | RMRKImplementationBase( 17 | name, 18 | symbol, 19 | collectionMetadata, 20 | maxSupply, 21 | address(0), 22 | 0 23 | ) 24 | {} 25 | 26 | function mockMint(uint256 total) external { 27 | _prepareMint(total); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKMinifiedEquippableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKMinifiedEquippable 7 | } from "../RMRK/equippable/RMRKMinifiedEquippable.sol"; 8 | 9 | //Minimal public implementation of RMRKEquippable for testing. 10 | contract RMRKMinifiedEquippableMock is RMRKMinifiedEquippable { 11 | function safeMint(address to, uint256 tokenId) public { 12 | _safeMint(to, tokenId, ""); 13 | } 14 | 15 | function safeMint(address to, uint256 tokenId, bytes memory _data) public { 16 | _safeMint(to, tokenId, _data); 17 | } 18 | 19 | function mint(address to, uint256 tokenId) external { 20 | _safeMint(to, tokenId, ""); 21 | } 22 | 23 | function nestMint( 24 | address to, 25 | uint256 tokenId, 26 | uint256 destinationId 27 | ) external { 28 | _nestMint(to, tokenId, destinationId, ""); 29 | } 30 | 31 | function addAssetToToken( 32 | uint256 tokenId, 33 | uint64 assetId, 34 | uint64 replacesAssetWithId 35 | ) external { 36 | _addAssetToToken(tokenId, assetId, replacesAssetWithId); 37 | } 38 | 39 | function addEquippableAssetEntry( 40 | uint64 id, 41 | uint64 equippableGroupId, 42 | address catalogAddress, 43 | string memory metadataURI, 44 | uint64[] calldata partIds 45 | ) external { 46 | _addAssetEntry( 47 | id, 48 | equippableGroupId, 49 | catalogAddress, 50 | metadataURI, 51 | partIds 52 | ); 53 | } 54 | 55 | function setValidParentForEquippableGroup( 56 | uint64 equippableGroupId, 57 | address parentAddress, 58 | uint64 partId 59 | ) external { 60 | _setValidParentForEquippableGroup( 61 | equippableGroupId, 62 | parentAddress, 63 | partId 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKMultiAssetAutoIndexMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKMultiAssetAutoIndex 7 | } from "../RMRK/extension/multiAssetAutoIndex/RMRKMultiAssetAutoIndex.sol"; 8 | 9 | contract RMRKMultiAssetAutoIndexMock is RMRKMultiAssetAutoIndex { 10 | function mint(address to, uint256 tokenId) external { 11 | _mint(to, tokenId); 12 | } 13 | 14 | function addAssetToToken( 15 | uint256 tokenId, 16 | uint64 assetId, 17 | uint64 replacesAssetWithId 18 | ) external { 19 | _addAssetToToken(tokenId, assetId, replacesAssetWithId); 20 | } 21 | 22 | function addAssetEntry(uint64 id, string memory metadataURI) external { 23 | _addAssetEntry(id, metadataURI); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKMultiAsset} from "../RMRK/multiasset/RMRKMultiAsset.sol"; 6 | 7 | contract RMRKMultiAssetMock is RMRKMultiAsset { 8 | function mint(address to, uint256 tokenId) external { 9 | _mint(to, tokenId); 10 | } 11 | 12 | function safeMint(address to, uint256 tokenId) external { 13 | _safeMint(to, tokenId, ""); 14 | } 15 | 16 | function safeMint(address to, uint256 tokenId, bytes memory data) external { 17 | _safeMint(to, tokenId, data); 18 | } 19 | 20 | function transfer(address to, uint256 tokenId) external { 21 | _transfer(_msgSender(), to, tokenId); 22 | } 23 | 24 | function burn(uint256 tokenId) external { 25 | _burn(tokenId); 26 | } 27 | 28 | function addAssetToToken( 29 | uint256 tokenId, 30 | uint64 assetId, 31 | uint64 replacesAssetWithId 32 | ) external { 33 | _addAssetToToken(tokenId, assetId, replacesAssetWithId); 34 | } 35 | 36 | function addAssetEntry(uint64 id, string memory metadataURI) external { 37 | _addAssetEntry(id, metadataURI); 38 | } 39 | 40 | function addAssetToTokensEventTest( 41 | uint256[] memory tokenIds, 42 | uint64 assetId, 43 | uint64 replacesAssetWithId 44 | ) external { 45 | emit AssetAddedToTokens(tokenIds, assetId, replacesAssetWithId); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKNestableAutoIndexMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKNestableAutoIndex 7 | } from "../RMRK/extension/nestableAutoIndex/RMRKNestableAutoIndex.sol"; 8 | 9 | contract RMRKNestableAutoIndexMock is RMRKNestableAutoIndex { 10 | function mint(address to, uint256 tokenId) external { 11 | _mint(to, tokenId, ""); 12 | } 13 | 14 | function nestMint( 15 | address to, 16 | uint256 tokenId, 17 | uint256 destinationId 18 | ) external { 19 | _nestMint(to, tokenId, destinationId, ""); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKNestableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {RMRKNestable} from "../RMRK/nestable/RMRKNestable.sol"; 6 | 7 | //Minimal public implementation of IERC7401 for testing. 8 | contract RMRKNestableMock is RMRKNestable { 9 | // This is used to test the usage of hooks 10 | mapping(address => mapping(uint256 => uint256)) private _balancesPerNft; 11 | 12 | function safeMint(address to, uint256 tokenId) public { 13 | _safeMint(to, tokenId, ""); 14 | } 15 | 16 | function safeMint(address to, uint256 tokenId, bytes memory _data) public { 17 | _safeMint(to, tokenId, _data); 18 | } 19 | 20 | function mint(address to, uint256 tokenId) external { 21 | _mint(to, tokenId, ""); 22 | } 23 | 24 | function nestMint( 25 | address to, 26 | uint256 tokenId, 27 | uint256 destinationId 28 | ) external { 29 | _nestMint(to, tokenId, destinationId, ""); 30 | } 31 | 32 | // Utility transfers: 33 | 34 | function transfer(address to, uint256 tokenId) public virtual { 35 | transferFrom(_msgSender(), to, tokenId); 36 | } 37 | 38 | function nestTransfer( 39 | address to, 40 | uint256 tokenId, 41 | uint256 destinationId 42 | ) public virtual { 43 | nestTransferFrom(_msgSender(), to, tokenId, destinationId, ""); 44 | } 45 | 46 | function _beforeNestedTokenTransfer( 47 | address from, 48 | address to, 49 | uint256 fromTokenId, 50 | uint256 toTokenId, 51 | uint256 tokenId, 52 | bytes memory data 53 | ) internal virtual override { 54 | super._beforeNestedTokenTransfer( 55 | from, 56 | to, 57 | fromTokenId, 58 | toTokenId, 59 | tokenId, 60 | data 61 | ); 62 | if (from != address(0)) _balancesPerNft[from][fromTokenId] -= 1; 63 | } 64 | 65 | function _afterNestedTokenTransfer( 66 | address from, 67 | address to, 68 | uint256 fromTokenId, 69 | uint256 toTokenId, 70 | uint256 tokenId, 71 | bytes memory data 72 | ) internal virtual override { 73 | super._afterNestedTokenTransfer( 74 | from, 75 | to, 76 | fromTokenId, 77 | toTokenId, 78 | tokenId, 79 | data 80 | ); 81 | if (to != address(0)) _balancesPerNft[to][toTokenId] += 1; 82 | } 83 | 84 | function balancePerNftOf( 85 | address owner, 86 | uint256 parentId 87 | ) public view returns (uint256) { 88 | return _balancesPerNft[owner][parentId]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /contracts/mocks/RMRKNestableMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKNestableMultiAsset 7 | } from "../RMRK/nestable/RMRKNestableMultiAsset.sol"; 8 | 9 | //Minimal public implementation of RMRKNestableMultiAsset for testing. 10 | contract RMRKNestableMultiAssetMock is RMRKNestableMultiAsset { 11 | function mint(address to, uint256 tokenId) external { 12 | _mint(to, tokenId, ""); 13 | } 14 | 15 | function safeMint(address to, uint256 tokenId) public { 16 | _safeMint(to, tokenId, ""); 17 | } 18 | 19 | function safeMint(address to, uint256 tokenId, bytes memory _data) public { 20 | _safeMint(to, tokenId, _data); 21 | } 22 | 23 | function nestMint( 24 | address to, 25 | uint256 tokenId, 26 | uint256 destinationId 27 | ) external { 28 | _nestMint(to, tokenId, destinationId, ""); 29 | } 30 | 31 | function addAssetToToken( 32 | uint256 tokenId, 33 | uint64 assetId, 34 | uint64 replacesAssetWithId 35 | ) external { 36 | _addAssetToToken(tokenId, assetId, replacesAssetWithId); 37 | } 38 | 39 | function addAssetEntry(uint64 id, string memory metadataURI) external { 40 | _addAssetEntry(id, metadataURI); 41 | } 42 | 43 | function transfer(address to, uint256 tokenId) public virtual { 44 | transferFrom(_msgSender(), to, tokenId); 45 | } 46 | 47 | function nestTransfer( 48 | address to, 49 | uint256 tokenId, 50 | uint256 destinationId 51 | ) public virtual { 52 | nestTransferFrom(_msgSender(), to, tokenId, destinationId, ""); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/claimableChild/RMRKNestableClaimableChildMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKReclaimableChild 7 | } from "../../../RMRK/extension/reclaimableChild/RMRKReclaimableChild.sol"; 8 | import {RMRKNestableMock} from "../../RMRKNestableMock.sol"; 9 | import {RMRKNestable} from "../../../RMRK/nestable/RMRKNestable.sol"; 10 | 11 | contract RMRKNestableClaimableChildMock is 12 | RMRKNestableMock, 13 | RMRKReclaimableChild 14 | { 15 | function supportsInterface( 16 | bytes4 interfaceId 17 | ) 18 | public 19 | view 20 | virtual 21 | override(RMRKNestable, RMRKReclaimableChild) 22 | returns (bool) 23 | { 24 | return super.supportsInterface(interfaceId); 25 | } 26 | 27 | function _beforeAddChild( 28 | uint256 tokenId, 29 | address childAddress, 30 | uint256 childId, 31 | bytes memory data 32 | ) internal virtual override(RMRKNestable, RMRKReclaimableChild) { 33 | super._beforeAddChild(tokenId, childAddress, childId, data); 34 | } 35 | 36 | function _beforeAcceptChild( 37 | uint256 parentId, 38 | uint256 childIndex, 39 | address childAddress, 40 | uint256 childId 41 | ) internal virtual override(RMRKNestable, RMRKReclaimableChild) { 42 | super._beforeAcceptChild(parentId, childIndex, childAddress, childId); 43 | } 44 | 45 | function _beforeTransferChild( 46 | uint256 tokenId, 47 | uint256 childIndex, 48 | address childAddress, 49 | uint256 childId, 50 | bool isPending, 51 | bytes memory data 52 | ) internal virtual override(RMRKNestable, RMRKReclaimableChild) { 53 | super._beforeTransferChild( 54 | tokenId, 55 | childIndex, 56 | childAddress, 57 | childId, 58 | isPending, 59 | data 60 | ); 61 | } 62 | 63 | function _beforeNestedTokenTransfer( 64 | address from, 65 | address to, 66 | uint256 fromTokenId, 67 | uint256 toTokenId, 68 | uint256 tokenId, 69 | bytes memory data 70 | ) internal override(RMRKNestableMock, RMRKNestable) { 71 | super._beforeNestedTokenTransfer( 72 | from, 73 | to, 74 | fromTokenId, 75 | toTokenId, 76 | tokenId, 77 | data 78 | ); 79 | } 80 | 81 | function _afterNestedTokenTransfer( 82 | address from, 83 | address to, 84 | uint256 fromTokenId, 85 | uint256 toTokenId, 86 | uint256 tokenId, 87 | bytes memory data 88 | ) internal override(RMRKNestableMock, RMRKNestable) { 89 | super._afterNestedTokenTransfer( 90 | from, 91 | to, 92 | fromTokenId, 93 | toTokenId, 94 | tokenId, 95 | data 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/revealable/RMRKMultiAssetRevealableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | IRMRKRevealable 7 | } from "../../../RMRK/extension/revealable/IRMRKRevealable.sol"; 8 | import { 9 | RMRKRevealable 10 | } from "../../../RMRK/extension/revealable/RMRKRevealable.sol"; 11 | import {RMRKMultiAssetMock} from "../../RMRKMultiAssetMock.sol"; 12 | import {RMRKMultiAsset} from "../../../RMRK/multiasset/RMRKMultiAsset.sol"; 13 | 14 | contract RMRKMultiAssetRevealableMock is RMRKMultiAssetMock, RMRKRevealable { 15 | function supportsInterface( 16 | bytes4 interfaceId 17 | ) 18 | public 19 | view 20 | virtual 21 | override(RMRKMultiAsset, RMRKRevealable) 22 | returns (bool) 23 | { 24 | return 25 | RMRKMultiAsset.supportsInterface(interfaceId) || 26 | RMRKRevealable.supportsInterface(interfaceId); 27 | } 28 | 29 | /** 30 | * @inheritdoc IRMRKRevealable 31 | */ 32 | function setRevealer(address revealer) external { 33 | _setRevealer(revealer); 34 | } 35 | 36 | /** 37 | * @inheritdoc RMRKRevealable 38 | */ 39 | function _addAndAcceptAssetToToken( 40 | uint256 tokenId, 41 | uint64 newAssetId, 42 | uint64 assetToReplaceId 43 | ) internal override { 44 | _addAssetToToken(tokenId, newAssetId, assetToReplaceId); 45 | _acceptAsset(tokenId, _pendingAssets[tokenId].length - 1, newAssetId); 46 | } 47 | 48 | /** 49 | * @inheritdoc RMRKRevealable 50 | */ 51 | function _checkRevealPermissions( 52 | uint256[] memory tokenIds 53 | ) internal view override { 54 | uint256 length = tokenIds.length; 55 | for (uint256 i; i < length; ) { 56 | _onlyApprovedForAssetsOrOwner(tokenIds[i]); 57 | unchecked { 58 | ++i; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/revealable/RMRKRevealerMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {Context} from "@openzeppelin/contracts/utils/Context.sol"; 6 | import { 7 | IRMRKRevealer 8 | } from "../../../RMRK/extension/revealable/IRMRKRevealer.sol"; 9 | import {RMRKMultiAssetMock} from "../../RMRKMultiAssetMock.sol"; 10 | 11 | error AlreadyRevealed(uint256 tokenId); 12 | error CallerIsNotRevealable(); 13 | 14 | contract RMRKRevealerMock is IRMRKRevealer, Context { 15 | uint64 private _revealedAssetId; 16 | address private _revealableContract; 17 | mapping(uint256 tokenId => bool revealed) private _revealed; 18 | 19 | constructor(uint64 revealedAssetId, address revealableContract) { 20 | _revealedAssetId = revealedAssetId; 21 | _revealableContract = revealableContract; 22 | } 23 | 24 | function supportsInterface( 25 | bytes4 interfaceId 26 | ) public view virtual returns (bool supportsInterface_) { 27 | supportsInterface_ = interfaceId == type(IRMRKRevealer).interfaceId; 28 | } 29 | 30 | /**- 31 | * @inheritdoc IRMRKRevealer 32 | */ 33 | function getRevealableTokens( 34 | uint256[] memory tokenIds 35 | ) external view returns (bool[] memory revealable) { 36 | uint256 length = tokenIds.length; 37 | revealable = new bool[](length); 38 | for (uint256 i; i < length; ) { 39 | revealable[i] = !_revealed[tokenIds[i]]; 40 | unchecked { 41 | ++i; 42 | } 43 | } 44 | } 45 | 46 | /**- 47 | * @inheritdoc IRMRKRevealer 48 | */ 49 | function reveal( 50 | uint256[] memory tokenIds 51 | ) 52 | external 53 | returns ( 54 | uint64[] memory revealedAssetsIds, 55 | uint64[] memory assetsToReplaceIds 56 | ) 57 | { 58 | if (_msgSender() != _revealableContract) { 59 | revert CallerIsNotRevealable(); 60 | } 61 | uint256 length = tokenIds.length; 62 | revealedAssetsIds = new uint64[](length); 63 | assetsToReplaceIds = new uint64[](length); 64 | for (uint256 i; i < length; ) { 65 | uint256 tokenId = tokenIds[i]; 66 | if (_revealed[tokenId]) { 67 | revert AlreadyRevealed(tokenId); 68 | } 69 | _revealed[tokenId] = true; 70 | uint64[] memory activeAssets = RMRKMultiAssetMock(_msgSender()) 71 | .getActiveAssets(tokenId); 72 | // Asumes that the token has at least one asset 73 | revealedAssetsIds[i] = _revealedAssetId; 74 | assetsToReplaceIds[i] = activeAssets[0]; 75 | unchecked { 76 | ++i; 77 | } 78 | } 79 | emit Revealed(tokenIds, revealedAssetsIds, assetsToReplaceIds); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/soulbound/RMRKSoulboundEquippableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKSoulbound 7 | } from "../../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 8 | import {RMRKNestable} from "../../../RMRK/nestable/RMRKNestable.sol"; 9 | import {RMRKEquippable} from "../../../RMRK/equippable/RMRKEquippable.sol"; 10 | import {RMRKEquippableMock} from "../../RMRKEquippableMock.sol"; 11 | 12 | contract RMRKSoulboundEquippableMock is RMRKSoulbound, RMRKEquippableMock { 13 | function supportsInterface( 14 | bytes4 interfaceId 15 | ) 16 | public 17 | view 18 | virtual 19 | override(RMRKSoulbound, RMRKEquippable) 20 | returns (bool) 21 | { 22 | return 23 | RMRKSoulbound.supportsInterface(interfaceId) || 24 | super.supportsInterface(interfaceId); 25 | } 26 | 27 | function _beforeTokenTransfer( 28 | address from, 29 | address to, 30 | uint256 tokenId 31 | ) internal virtual override(RMRKNestable, RMRKSoulbound) { 32 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 33 | RMRKNestable._beforeTokenTransfer(from, to, tokenId); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/soulbound/RMRKSoulboundMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKSoulbound 7 | } from "../../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 8 | import {RMRKMultiAsset} from "../../../RMRK/multiasset/RMRKMultiAsset.sol"; 9 | import {RMRKMultiAssetMock} from "../../RMRKMultiAssetMock.sol"; 10 | 11 | contract RMRKSoulboundMultiAssetMock is RMRKSoulbound, RMRKMultiAssetMock { 12 | function supportsInterface( 13 | bytes4 interfaceId 14 | ) 15 | public 16 | view 17 | virtual 18 | override(RMRKSoulbound, RMRKMultiAsset) 19 | returns (bool) 20 | { 21 | return 22 | RMRKSoulbound.supportsInterface(interfaceId) || 23 | super.supportsInterface(interfaceId); 24 | } 25 | 26 | function _beforeTokenTransfer( 27 | address from, 28 | address to, 29 | uint256 tokenId 30 | ) internal virtual override(RMRKMultiAsset, RMRKSoulbound) { 31 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 32 | RMRKMultiAsset._beforeTokenTransfer(from, to, tokenId); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/soulbound/RMRKSoulboundNestableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKSoulbound 7 | } from "../../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 8 | import {RMRKNestable} from "../../../RMRK/nestable/RMRKNestable.sol"; 9 | import {RMRKNestableMock} from "../../RMRKNestableMock.sol"; 10 | 11 | contract RMRKSoulboundNestableMock is RMRKSoulbound, RMRKNestableMock { 12 | function supportsInterface( 13 | bytes4 interfaceId 14 | ) public view virtual override(RMRKSoulbound, RMRKNestable) returns (bool) { 15 | return 16 | RMRKSoulbound.supportsInterface(interfaceId) || 17 | super.supportsInterface(interfaceId); 18 | } 19 | 20 | function _beforeTokenTransfer( 21 | address from, 22 | address to, 23 | uint256 tokenId 24 | ) internal virtual override(RMRKNestable, RMRKSoulbound) { 25 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 26 | RMRKNestable._beforeTokenTransfer(from, to, tokenId); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/soulbound/RMRKSoulboundNestableMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKSoulbound 7 | } from "../../../RMRK/extension/soulbound/RMRKSoulbound.sol"; 8 | import {RMRKNestable} from "../../../RMRK/nestable/RMRKNestable.sol"; 9 | import { 10 | RMRKNestableMultiAsset 11 | } from "../../../RMRK/nestable/RMRKNestableMultiAsset.sol"; 12 | import {RMRKNestableMultiAssetMock} from "../../RMRKNestableMultiAssetMock.sol"; 13 | 14 | contract RMRKSoulboundNestableMultiAssetMock is 15 | RMRKSoulbound, 16 | RMRKNestableMultiAssetMock 17 | { 18 | function supportsInterface( 19 | bytes4 interfaceId 20 | ) 21 | public 22 | view 23 | virtual 24 | override(RMRKSoulbound, RMRKNestableMultiAsset) 25 | returns (bool) 26 | { 27 | return 28 | RMRKSoulbound.supportsInterface(interfaceId) || 29 | super.supportsInterface(interfaceId); 30 | } 31 | 32 | function _beforeTokenTransfer( 33 | address from, 34 | address to, 35 | uint256 tokenId 36 | ) internal virtual override(RMRKNestable, RMRKSoulbound) { 37 | RMRKSoulbound._beforeTokenTransfer(from, to, tokenId); 38 | RMRKNestable._beforeTokenTransfer(from, to, tokenId); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/tokenHolder/RMRKTokenHolderMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | import { 7 | RMRKTokenHolder 8 | } from "../../../RMRK/extension/tokenHolder/RMRKTokenHolder.sol"; 9 | import {IERC7590} from "../../../RMRK/extension/tokenHolder/IERC7590.sol"; 10 | 11 | error OnlyNFTOwnerCanTransferTokensFromIt(); 12 | 13 | /** 14 | * @title RMRKTokenHolderMock 15 | * @author RMRK team 16 | * @notice Smart contract of the RMRK ERC20 Holder module. 17 | */ 18 | contract RMRKTokenHolderMock is RMRKTokenHolder, ERC721 { 19 | constructor( 20 | string memory name, 21 | string memory symbol 22 | ) ERC721(name, symbol) {} 23 | 24 | function mint(address to, uint256 tokenId) public { 25 | _mint(to, tokenId); 26 | } 27 | 28 | function supportsInterface( 29 | bytes4 interfaceId 30 | ) public view virtual override(RMRKTokenHolder, ERC721) returns (bool) { 31 | return 32 | RMRKTokenHolder.supportsInterface(interfaceId) || 33 | super.supportsInterface(interfaceId); 34 | } 35 | 36 | /** 37 | * @inheritdoc IERC7590 38 | */ 39 | function transferHeldERC20FromToken( 40 | address erc20Contract, 41 | uint256 tokenHolderId, 42 | address to, 43 | uint256 amount, 44 | bytes memory data 45 | ) external { 46 | if (msg.sender != ownerOf(tokenHolderId)) { 47 | revert OnlyNFTOwnerCanTransferTokensFromIt(); 48 | } 49 | _transferHeldERC20FromToken( 50 | erc20Contract, 51 | tokenHolderId, 52 | to, 53 | amount, 54 | data 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/typedMultiAsset/RMRKNestableTypedMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKTypedMultiAsset 7 | } from "../../../RMRK/extension/typedMultiAsset/RMRKTypedMultiAsset.sol"; 8 | import {RMRKNestableMultiAssetMock} from "../../RMRKNestableMultiAssetMock.sol"; 9 | import { 10 | RMRKNestableMultiAsset 11 | } from "../../../RMRK/nestable/RMRKNestableMultiAsset.sol"; 12 | 13 | contract RMRKNestableTypedMultiAssetMock is 14 | RMRKNestableMultiAssetMock, 15 | RMRKTypedMultiAsset 16 | { 17 | function supportsInterface( 18 | bytes4 interfaceId 19 | ) 20 | public 21 | view 22 | virtual 23 | override(RMRKNestableMultiAsset, RMRKTypedMultiAsset) 24 | returns (bool) 25 | { 26 | return 27 | RMRKTypedMultiAsset.supportsInterface(interfaceId) || 28 | RMRKNestableMultiAsset.supportsInterface(interfaceId); 29 | } 30 | 31 | function addTypedAssetEntry( 32 | uint64 assetId, 33 | string memory metadataURI, 34 | string memory type_ 35 | ) external { 36 | _addAssetEntry(assetId, metadataURI); 37 | _setAssetType(assetId, type_); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/typedMultiAsset/RMRKTypedEquippableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKTypedMultiAsset 7 | } from "../../../RMRK/extension/typedMultiAsset/RMRKTypedMultiAsset.sol"; 8 | import {RMRKEquippableMock} from "../../RMRKEquippableMock.sol"; 9 | import {RMRKEquippable} from "../../../RMRK/equippable/RMRKEquippable.sol"; 10 | 11 | contract RMRKTypedEquippableMock is RMRKEquippableMock, RMRKTypedMultiAsset { 12 | function supportsInterface( 13 | bytes4 interfaceId 14 | ) 15 | public 16 | view 17 | virtual 18 | override(RMRKEquippable, RMRKTypedMultiAsset) 19 | returns (bool) 20 | { 21 | return 22 | RMRKTypedMultiAsset.supportsInterface(interfaceId) || 23 | RMRKEquippable.supportsInterface(interfaceId); 24 | } 25 | 26 | function addTypedAssetEntry( 27 | uint64 id, 28 | uint64 equippableGroupId, 29 | address catalogAddress, 30 | string memory metadataURI, 31 | uint64[] calldata partIds, 32 | string memory type_ 33 | ) external { 34 | _addAssetEntry( 35 | id, 36 | equippableGroupId, 37 | catalogAddress, 38 | metadataURI, 39 | partIds 40 | ); 41 | _setAssetType(id, type_); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/mocks/extensions/typedMultiAsset/RMRKTypedMultiAssetMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import { 6 | RMRKTypedMultiAsset 7 | } from "../../../RMRK/extension/typedMultiAsset/RMRKTypedMultiAsset.sol"; 8 | import {RMRKMultiAssetMock} from "../../RMRKMultiAssetMock.sol"; 9 | import {RMRKMultiAsset} from "../../../RMRK/multiasset/RMRKMultiAsset.sol"; 10 | 11 | error RMRKTokenHasNoAssetsWithType(); 12 | 13 | contract RMRKTypedMultiAssetMock is RMRKMultiAssetMock, RMRKTypedMultiAsset { 14 | uint64 private constant _LOWEST_POSSIBLE_PRIORITY = 2 ** 64 - 1; 15 | 16 | function supportsInterface( 17 | bytes4 interfaceId 18 | ) 19 | public 20 | view 21 | virtual 22 | override(RMRKMultiAsset, RMRKTypedMultiAsset) 23 | returns (bool) 24 | { 25 | return 26 | RMRKTypedMultiAsset.supportsInterface(interfaceId) || 27 | RMRKMultiAsset.supportsInterface(interfaceId); 28 | } 29 | 30 | function addTypedAssetEntry( 31 | uint64 assetId, 32 | string memory metadataURI, 33 | string memory type_ 34 | ) external { 35 | _addAssetEntry(assetId, metadataURI); 36 | _setAssetType(assetId, type_); 37 | } 38 | 39 | function getTopAssetMetaForTokenWithType( 40 | uint256 tokenId, 41 | string memory type_ 42 | ) external view returns (string memory) { 43 | uint64[] memory priorities = getActiveAssetPriorities(tokenId); 44 | uint64[] memory assets = getActiveAssets(tokenId); 45 | uint256 len = priorities.length; 46 | 47 | uint64 maxPriority = _LOWEST_POSSIBLE_PRIORITY; 48 | uint64 maxPriorityAsset; 49 | bytes32 targetTypeEncoded = keccak256(bytes(type_)); 50 | for (uint64 i; i < len; ) { 51 | uint64 currentPrio = priorities[i]; 52 | bytes32 assetTypeEncoded = keccak256( 53 | bytes(getAssetType(assets[i])) 54 | ); 55 | if ( 56 | assetTypeEncoded == targetTypeEncoded && 57 | currentPrio < maxPriority 58 | ) { 59 | maxPriority = currentPrio; 60 | maxPriorityAsset = assets[i]; 61 | } 62 | unchecked { 63 | ++i; 64 | } 65 | } 66 | if (maxPriority == _LOWEST_POSSIBLE_PRIORITY) 67 | revert RMRKTokenHasNoAssetsWithType(); 68 | return getAssetMetadata(tokenId, maxPriorityAsset); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/security_mocks/ChildAdder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | pragma solidity ^0.8.21; 4 | 5 | import {IERC7401} from "../RMRK/nestable/IERC7401.sol"; 6 | 7 | /** 8 | * @title ChildAdder 9 | * @author RMRK team 10 | * @notice Smart contract of the child adder module. 11 | * @dev This smart contract is used to easily add a desired amount of child tokens to a desired token. 12 | */ 13 | contract ChildAdder { 14 | /** 15 | * @notice Used to add a specified amount of child tokens with the same IO to a given token. 16 | * @param destContract The address of the smart contract of the token to which to add new child tokens 17 | * @param parentId ID of the token to which to add the child tokens 18 | * @param childId ID of the child tokens to be added 19 | * @param numChildren The number of child tokens to add 20 | */ 21 | function addChild( 22 | address destContract, 23 | uint256 parentId, 24 | uint256 childId, 25 | uint256 numChildren 26 | ) external { 27 | for (uint256 i; i < numChildren; ) { 28 | IERC7401(destContract).addChild(parentId, childId, ""); 29 | unchecked { 30 | ++i; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/RMRK/core/IRMRKCore.md: -------------------------------------------------------------------------------- 1 | # IRMRKCore 2 | 3 | *RMRK team* 4 | 5 | > IRMRKCore 6 | 7 | Interface smart contract for RMRK core module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### name 14 | 15 | ```solidity 16 | function name() external view returns (string) 17 | ``` 18 | 19 | Used to retrieve the collection name. 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | string | Name of the collection | 29 | 30 | ### symbol 31 | 32 | ```solidity 33 | function symbol() external view returns (string) 34 | ``` 35 | 36 | Used to retrieve the collection symbol. 37 | 38 | 39 | 40 | 41 | #### Returns 42 | 43 | | Name | Type | Description | 44 | |---|---|---| 45 | | _0 | string | Symbol of the collection | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/RMRK/core/RMRKCore.md: -------------------------------------------------------------------------------- 1 | # RMRKCore 2 | 3 | *RMRK team* 4 | 5 | > RMRKCore 6 | 7 | Smart contract of the RMRK core module. 8 | 9 | *This is currently just a passthrough contract which allows for granular editing of base-level ERC721 functions.* 10 | 11 | ## Methods 12 | 13 | ### RMRK_INTERFACE 14 | 15 | ```solidity 16 | function RMRK_INTERFACE() external pure returns (bytes4 rmrkInterface) 17 | ``` 18 | 19 | Interface identifier of the @rmrk-team/evm-contracts package 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | rmrkInterface | bytes4 | Interface identifier for implementations of the @rmrk-team/evm-contracts package | 29 | 30 | ### VERSION 31 | 32 | ```solidity 33 | function VERSION() external pure returns (string version) 34 | ``` 35 | 36 | Version of the @rmrk-team/evm-contracts package 37 | 38 | 39 | 40 | 41 | #### Returns 42 | 43 | | Name | Type | Description | 44 | |---|---|---| 45 | | version | string | Version identifier for implementations of the @rmrk-team/evm-contracts package | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/RMRK/extension/RMRKRoyalties.md: -------------------------------------------------------------------------------- 1 | # RMRKRoyalties 2 | 3 | *RMRK team* 4 | 5 | > RMRKRoyalties 6 | 7 | Smart contract of the RMRK Royalties module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getRoyaltyPercentage 14 | 15 | ```solidity 16 | function getRoyaltyPercentage() external view returns (uint256 royaltyPercentageBps) 17 | ``` 18 | 19 | Used to retrieve the specified royalty percentage. 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | royaltyPercentageBps | uint256 | The royalty percentage expressed in the basis points | 29 | 30 | ### getRoyaltyRecipient 31 | 32 | ```solidity 33 | function getRoyaltyRecipient() external view returns (address recipient) 34 | ``` 35 | 36 | Used to retrieve the recipient of royalties. 37 | 38 | 39 | 40 | 41 | #### Returns 42 | 43 | | Name | Type | Description | 44 | |---|---|---| 45 | | recipient | address | Address of the recipient of royalties | 46 | 47 | ### royaltyInfo 48 | 49 | ```solidity 50 | function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) 51 | ``` 52 | 53 | Used to retrieve the information about who shall receive royalties of a sale of the specified token and how much they will be. 54 | 55 | 56 | 57 | #### Parameters 58 | 59 | | Name | Type | Description | 60 | |---|---|---| 61 | | tokenId | uint256 | ID of the token for which the royalty info is being retrieved | 62 | | salePrice | uint256 | Price of the token sale | 63 | 64 | #### Returns 65 | 66 | | Name | Type | Description | 67 | |---|---|---| 68 | | receiver | address | The beneficiary receiving royalties of the sale | 69 | | royaltyAmount | uint256 | The value of the royalties recieved by the `receiver` from the sale | 70 | 71 | ### updateRoyaltyRecipient 72 | 73 | ```solidity 74 | function updateRoyaltyRecipient(address newRoyaltyRecipient) external nonpayable 75 | ``` 76 | 77 | Used to update recipient of royalties. 78 | 79 | *Custom access control has to be implemented to ensure that only the intended actors can update the beneficiary.* 80 | 81 | #### Parameters 82 | 83 | | Name | Type | Description | 84 | |---|---|---| 85 | | newRoyaltyRecipient | address | Address of the new recipient of royalties | 86 | 87 | 88 | 89 | 90 | ## Errors 91 | 92 | ### RMRKRoyaltiesTooHigh 93 | 94 | ```solidity 95 | error RMRKRoyaltiesTooHigh() 96 | ``` 97 | 98 | Attempting to set the royalties to a value higher than 100% (10000 in basis points) 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /docs/RMRK/extension/reclaimableChild/IRMRKReclaimableChild.md: -------------------------------------------------------------------------------- 1 | # IRMRKReclaimableChild 2 | 3 | *RMRK team* 4 | 5 | > IRMRKReclaimableChild 6 | 7 | Interface smart contract of the RMRK Reclaimable child module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### reclaimChild 14 | 15 | ```solidity 16 | function reclaimChild(uint256 tokenId, address childAddress, uint256 childId) external nonpayable 17 | ``` 18 | 19 | Used to reclaim an abandoned child token. 20 | 21 | *Child token was abandoned by transferring it with `to` as the `0x0` address.This function will set the child's owner to the `rootOwner` of the caller, allowing the `rootOwner` management permissions for the child.Requirements: - `tokenId` must exist* 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the last parent token of the child token being recovered | 28 | | childAddress | address | Address of the child token's smart contract | 29 | | childId | uint256 | ID of the child token being reclaimed | 30 | 31 | ### supportsInterface 32 | 33 | ```solidity 34 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 35 | ``` 36 | 37 | 38 | 39 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 40 | 41 | #### Parameters 42 | 43 | | Name | Type | Description | 44 | |---|---|---| 45 | | interfaceId | bytes4 | undefined | 46 | 47 | #### Returns 48 | 49 | | Name | Type | Description | 50 | |---|---|---| 51 | | _0 | bool | undefined | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/RMRK/extension/revealable/IRMRKRevealable.md: -------------------------------------------------------------------------------- 1 | # IRMRKRevealable 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getRevealer 14 | 15 | ```solidity 16 | function getRevealer() external view returns (address revealer) 17 | ``` 18 | 19 | Gets the `IRMRKRevealer` associated with the contract. 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | revealer | address | The `IRMRKRevealer` associated with the contract | 29 | 30 | ### reveal 31 | 32 | ```solidity 33 | function reveal(uint256[] tokenIds) external nonpayable 34 | ``` 35 | 36 | Reveals the asset for the given tokenIds by adding and accepting and new one. 37 | 38 | *SHOULD ask revealer which assetId should be added to the token and which asset to replace through `IRMRKRevealer.getAssetsToReveal`SHOULD be called by the owner or approved for assetsSHOULD add the new asset to each token and accept it* 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | |---|---|---| 44 | | tokenIds | uint256[] | undefined | 45 | 46 | ### setRevealer 47 | 48 | ```solidity 49 | function setRevealer(address revealer) external nonpayable 50 | ``` 51 | 52 | Sets the `IRMRKRevealer` associated with the contract. 53 | 54 | 55 | 56 | #### Parameters 57 | 58 | | Name | Type | Description | 59 | |---|---|---| 60 | | revealer | address | The `IRMRKRevealer` to associate with the contract | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/RMRK/extension/revealable/IRMRKRevealer.md: -------------------------------------------------------------------------------- 1 | # IRMRKRevealer 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getRevealableTokens 14 | 15 | ```solidity 16 | function getRevealableTokens(uint256[] tokenIds) external view returns (bool[] revealable) 17 | ``` 18 | 19 | For each `tokenId` in `tokenIds` returns whether it can be revealed or not 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenIds | uint256[] | The `tokenIds` to check | 28 | 29 | #### Returns 30 | 31 | | Name | Type | Description | 32 | |---|---|---| 33 | | revealable | bool[] | The array of booleans indicating whether each `tokenId` can be revealed or not | 34 | 35 | ### reveal 36 | 37 | ```solidity 38 | function reveal(uint256[] tokenIds) external nonpayable returns (uint64[] revealedAssetsIds, uint64[] assetsToReplaceIds) 39 | ``` 40 | 41 | Returns the revealed `assetIds` for the given `tokenIds` and marks them as revealed. 42 | 43 | *This CAN add new assets to the original contract if necessary, in which case it SHOULD have the necessary permissionsThis method MUST only return existing `assetIds`This method MUST be called only by the contract implementing the `IRMRKRevealable` interface, during the `reveal` methodThis method MUST return the same amount of `revealedAssetsIds` and `assetsToReplaceIds` as `tokenIds`* 44 | 45 | #### Parameters 46 | 47 | | Name | Type | Description | 48 | |---|---|---| 49 | | tokenIds | uint256[] | The `tokenIds` to reveal | 50 | 51 | #### Returns 52 | 53 | | Name | Type | Description | 54 | |---|---|---| 55 | | revealedAssetsIds | uint64[] | The revealed `assetIds` | 56 | | assetsToReplaceIds | uint64[] | The `assetIds` to replace | 57 | 58 | 59 | 60 | ## Events 61 | 62 | ### Revealed 63 | 64 | ```solidity 65 | event Revealed(uint256[] indexed tokenIds, uint64[] revealedAssetsIds, uint64[] assetsToReplaceIds) 66 | ``` 67 | 68 | 69 | 70 | 71 | 72 | #### Parameters 73 | 74 | | Name | Type | Description | 75 | |---|---|---| 76 | | tokenIds `indexed` | uint256[] | undefined | 77 | | revealedAssetsIds | uint64[] | undefined | 78 | | assetsToReplaceIds | uint64[] | undefined | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/RMRK/extension/revealable/RMRKRevealable.md: -------------------------------------------------------------------------------- 1 | # RMRKRevealable 2 | 3 | *RMRK team* 4 | 5 | > IRMRKRevealable 6 | 7 | Interface smart contract of the RMRK Revealable extension. This extension simplifies the process of revealing. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getRevealer 14 | 15 | ```solidity 16 | function getRevealer() external view returns (address) 17 | ``` 18 | 19 | Returns the address of the revealer contract 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | address | undefined | 29 | 30 | ### reveal 31 | 32 | ```solidity 33 | function reveal(uint256[] tokenIds) external nonpayable 34 | ``` 35 | 36 | Reveals the assets for the given tokenIds 37 | 38 | *This method SHOULD be called by the owner or approved for assetsThis method SHOULD add the asset to the token and accept itThis method SHOULD get the `assetId` to add and replace from the revealer contractThis `assetId` to replace CAN be 0, meaning that the asset is added to the token without replacing anythingThe revealer contract MUST take care of ensuring the `assetId` exists on the contract implementating this interface* 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | |---|---|---| 44 | | tokenIds | uint256[] | The tokenIds to reveal | 45 | 46 | ### setRevealer 47 | 48 | ```solidity 49 | function setRevealer(address revealer) external nonpayable 50 | ``` 51 | 52 | Sets the `IRMRKRevealer` associated with the contract. 53 | 54 | 55 | 56 | #### Parameters 57 | 58 | | Name | Type | Description | 59 | |---|---|---| 60 | | revealer | address | The `IRMRKRevealer` to associate with the contract | 61 | 62 | ### supportsInterface 63 | 64 | ```solidity 65 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 66 | ``` 67 | 68 | 69 | 70 | 71 | 72 | #### Parameters 73 | 74 | | Name | Type | Description | 75 | |---|---|---| 76 | | interfaceId | bytes4 | undefined | 77 | 78 | #### Returns 79 | 80 | | Name | Type | Description | 81 | |---|---|---| 82 | | _0 | bool | undefined | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/RMRK/extension/soulbound/IERC6454.md: -------------------------------------------------------------------------------- 1 | # IERC6454 2 | 3 | *RMRK team* 4 | 5 | > IERC6454 6 | 7 | A minimal extension to identify the transferability of Non-Fungible Tokens. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### isTransferable 14 | 15 | ```solidity 16 | function isTransferable(uint256 tokenId, address from, address to) external view returns (bool isTransferable_) 17 | ``` 18 | 19 | Used to check whether the given token is transferable or not. 20 | 21 | *If this function returns `false`, the transfer of the token MUST revert execution.If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for minting.* 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the token being checked | 28 | | from | address | Address from which the token is being transferred | 29 | | to | address | Address to which the token is being transferred | 30 | 31 | #### Returns 32 | 33 | | Name | Type | Description | 34 | |---|---|---| 35 | | isTransferable_ | bool | Boolean value indicating whether the given token is transferable | 36 | 37 | ### supportsInterface 38 | 39 | ```solidity 40 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 41 | ``` 42 | 43 | 44 | 45 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 46 | 47 | #### Parameters 48 | 49 | | Name | Type | Description | 50 | |---|---|---| 51 | | interfaceId | bytes4 | undefined | 52 | 53 | #### Returns 54 | 55 | | Name | Type | Description | 56 | |---|---|---| 57 | | _0 | bool | undefined | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/RMRK/extension/soulbound/RMRKSoulbound.md: -------------------------------------------------------------------------------- 1 | # RMRKSoulbound 2 | 3 | *RMRK team* 4 | 5 | > RMRKSoulbound 6 | 7 | Smart contract of the RMRK Soulbound module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### isTransferable 14 | 15 | ```solidity 16 | function isTransferable(uint256, address from, address to) external view returns (bool isTransferable_) 17 | ``` 18 | 19 | Used to check whether the given token is transferable or not. 20 | 21 | *If this function returns `false`, the transfer of the token MUST revert execution.If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for minting.* 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | _0 | uint256 | undefined | 28 | | from | address | Address from which the token is being transferred | 29 | | to | address | Address to which the token is being transferred | 30 | 31 | #### Returns 32 | 33 | | Name | Type | Description | 34 | |---|---|---| 35 | | isTransferable_ | bool | Boolean value indicating whether the given token is transferable | 36 | 37 | ### supportsInterface 38 | 39 | ```solidity 40 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 41 | ``` 42 | 43 | 44 | 45 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 46 | 47 | #### Parameters 48 | 49 | | Name | Type | Description | 50 | |---|---|---| 51 | | interfaceId | bytes4 | undefined | 52 | 53 | #### Returns 54 | 55 | | Name | Type | Description | 56 | |---|---|---| 57 | | _0 | bool | undefined | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/RMRK/extension/soulbound/RMRKSoulboundAfterBlockNumber.md: -------------------------------------------------------------------------------- 1 | # RMRKSoulboundAfterBlockNumber 2 | 3 | *RMRK team* 4 | 5 | > RMRKSoulboundAfterBlockNumber 6 | 7 | Smart contract of the RMRK Soulbound module where transfers are only allowed until a certain block number. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getLastBlockToTransfer 14 | 15 | ```solidity 16 | function getLastBlockToTransfer() external view returns (uint256) 17 | ``` 18 | 19 | Gets the last block number where transfers are allowed 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | uint256 | The block number after which tokens are soulbound | 29 | 30 | ### isTransferable 31 | 32 | ```solidity 33 | function isTransferable(uint256, address, address) external view returns (bool isTransferable_) 34 | ``` 35 | 36 | Used to check whether the given token is transferable or not. 37 | 38 | *If this function returns `false`, the transfer of the token MUST revert execution.If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for minting.* 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | |---|---|---| 44 | | _0 | uint256 | undefined | 45 | | _1 | address | undefined | 46 | | _2 | address | undefined | 47 | 48 | #### Returns 49 | 50 | | Name | Type | Description | 51 | |---|---|---| 52 | | isTransferable_ | bool | Boolean value indicating whether the given token is transferable | 53 | 54 | ### supportsInterface 55 | 56 | ```solidity 57 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 58 | ``` 59 | 60 | 61 | 62 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 63 | 64 | #### Parameters 65 | 66 | | Name | Type | Description | 67 | |---|---|---| 68 | | interfaceId | bytes4 | undefined | 69 | 70 | #### Returns 71 | 72 | | Name | Type | Description | 73 | |---|---|---| 74 | | _0 | bool | undefined | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /docs/RMRK/extension/soulbound/RMRKSoulboundAfterTransactions.md: -------------------------------------------------------------------------------- 1 | # RMRKSoulboundAfterTransactions 2 | 3 | *RMRK team* 4 | 5 | > RMRKSoulboundAfterTransactions 6 | 7 | Smart contract of the RMRK Soulbound module where transfers are allowed for a limited a number of transfers. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getMaxNumberOfTransfers 14 | 15 | ```solidity 16 | function getMaxNumberOfTransfers() external view returns (uint256) 17 | ``` 18 | 19 | Gets the maximum number of transfers before a token becomes soulbound. 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | uint256 | Maximum number of transfers before a token becomes soulbound | 29 | 30 | ### getTransfersPerToken 31 | 32 | ```solidity 33 | function getTransfersPerToken(uint256 tokenId) external view returns (uint256) 34 | ``` 35 | 36 | Gets the current number of transfer the specified token. 37 | 38 | 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | |---|---|---| 44 | | tokenId | uint256 | ID of the token | 45 | 46 | #### Returns 47 | 48 | | Name | Type | Description | 49 | |---|---|---| 50 | | _0 | uint256 | Number of the token's transfers to date | 51 | 52 | ### isTransferable 53 | 54 | ```solidity 55 | function isTransferable(uint256 tokenId, address, address) external view returns (bool isTransferable_) 56 | ``` 57 | 58 | Used to check whether the given token is transferable or not. 59 | 60 | *If this function returns `false`, the transfer of the token MUST revert execution.If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for minting.* 61 | 62 | #### Parameters 63 | 64 | | Name | Type | Description | 65 | |---|---|---| 66 | | tokenId | uint256 | ID of the token being checked | 67 | | _1 | address | undefined | 68 | | _2 | address | undefined | 69 | 70 | #### Returns 71 | 72 | | Name | Type | Description | 73 | |---|---|---| 74 | | isTransferable_ | bool | Boolean value indicating whether the given token is transferable | 75 | 76 | ### supportsInterface 77 | 78 | ```solidity 79 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 80 | ``` 81 | 82 | 83 | 84 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 85 | 86 | #### Parameters 87 | 88 | | Name | Type | Description | 89 | |---|---|---| 90 | | interfaceId | bytes4 | undefined | 91 | 92 | #### Returns 93 | 94 | | Name | Type | Description | 95 | |---|---|---| 96 | | _0 | bool | undefined | 97 | 98 | 99 | 100 | ## Events 101 | 102 | ### Soulbound 103 | 104 | ```solidity 105 | event Soulbound(uint256 indexed tokenId) 106 | ``` 107 | 108 | Emitted when a token becomes soulbound. 109 | 110 | 111 | 112 | #### Parameters 113 | 114 | | Name | Type | Description | 115 | |---|---|---| 116 | | tokenId `indexed` | uint256 | ID of the token | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /docs/RMRK/extension/soulbound/RMRKSoulboundPerToken.md: -------------------------------------------------------------------------------- 1 | # RMRKSoulboundPerToken 2 | 3 | *RMRK team* 4 | 5 | > RMRKSoulboundPerToken 6 | 7 | Smart contract of the RMRK Soulbound module where the transfers are permitted or prohibited on a per-token basis. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### isTransferable 14 | 15 | ```solidity 16 | function isTransferable(uint256 tokenId, address from, address to) external view returns (bool isTransferable_) 17 | ``` 18 | 19 | Used to check whether the given token is transferable or not. 20 | 21 | *If this function returns `false`, the transfer of the token MUST revert execution.If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for minting.* 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the token being checked | 28 | | from | address | Address from which the token is being transferred | 29 | | to | address | Address to which the token is being transferred | 30 | 31 | #### Returns 32 | 33 | | Name | Type | Description | 34 | |---|---|---| 35 | | isTransferable_ | bool | Boolean value indicating whether the given token is transferable | 36 | 37 | ### supportsInterface 38 | 39 | ```solidity 40 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 41 | ``` 42 | 43 | 44 | 45 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 46 | 47 | #### Parameters 48 | 49 | | Name | Type | Description | 50 | |---|---|---| 51 | | interfaceId | bytes4 | undefined | 52 | 53 | #### Returns 54 | 55 | | Name | Type | Description | 56 | |---|---|---| 57 | | _0 | bool | undefined | 58 | 59 | 60 | 61 | ## Events 62 | 63 | ### Soulbound 64 | 65 | ```solidity 66 | event Soulbound(uint256 indexed tokenId, bool state) 67 | ``` 68 | 69 | Emitted when a token's soulbound state changes. 70 | 71 | 72 | 73 | #### Parameters 74 | 75 | | Name | Type | Description | 76 | |---|---|---| 77 | | tokenId `indexed` | uint256 | ID of the token | 78 | | state | bool | A boolean value signifying whether the token became soulbound (`true`) or transferrable (`false`) | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/RMRK/extension/typedMultiAsset/IRMRKTypedMultiAsset.md: -------------------------------------------------------------------------------- 1 | # IRMRKTypedMultiAsset 2 | 3 | *RMRK team* 4 | 5 | > IRMRKTypedMultiAsset 6 | 7 | Interface smart contract of the RMRK typed multi asset module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getAssetType 14 | 15 | ```solidity 16 | function getAssetType(uint64 assetId) external view returns (string) 17 | ``` 18 | 19 | Used to get the type of the asset. 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | assetId | uint64 | ID of the asset to check | 28 | 29 | #### Returns 30 | 31 | | Name | Type | Description | 32 | |---|---|---| 33 | | _0 | string | The type of the asset | 34 | 35 | ### supportsInterface 36 | 37 | ```solidity 38 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 39 | ``` 40 | 41 | 42 | 43 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 44 | 45 | #### Parameters 46 | 47 | | Name | Type | Description | 48 | |---|---|---| 49 | | interfaceId | bytes4 | undefined | 50 | 51 | #### Returns 52 | 53 | | Name | Type | Description | 54 | |---|---|---| 55 | | _0 | bool | undefined | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/RMRK/extension/typedMultiAsset/RMRKTypedMultiAsset.md: -------------------------------------------------------------------------------- 1 | # RMRKTypedMultiAsset 2 | 3 | *RMRK team* 4 | 5 | > RMRKTypedMultiAsset 6 | 7 | Smart contract of the RMRK Typed multi asset module. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### getAssetType 14 | 15 | ```solidity 16 | function getAssetType(uint64 assetId) external view returns (string) 17 | ``` 18 | 19 | Used to get the type of the asset. 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | assetId | uint64 | ID of the asset to check | 28 | 29 | #### Returns 30 | 31 | | Name | Type | Description | 32 | |---|---|---| 33 | | _0 | string | The type of the asset | 34 | 35 | ### supportsInterface 36 | 37 | ```solidity 38 | function supportsInterface(bytes4 interfaceId) external view returns (bool) 39 | ``` 40 | 41 | 42 | 43 | *Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.* 44 | 45 | #### Parameters 46 | 47 | | Name | Type | Description | 48 | |---|---|---| 49 | | interfaceId | bytes4 | undefined | 50 | 51 | #### Returns 52 | 53 | | Name | Type | Description | 54 | |---|---|---| 55 | | _0 | bool | undefined | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/RMRK/library/RMRKLib.md: -------------------------------------------------------------------------------- 1 | # RMRKLib 2 | 3 | *RMRK team* 4 | 5 | > RMRKLib 6 | 7 | RMRK library smart contract. 8 | 9 | 10 | 11 | 12 | 13 | ## Errors 14 | 15 | ### IndexOutOfBounds 16 | 17 | ```solidity 18 | error IndexOutOfBounds() 19 | ``` 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/RMRK/security/ReentrancyGuard.md: -------------------------------------------------------------------------------- 1 | # ReentrancyGuard 2 | 3 | 4 | 5 | > ReentrancyGuard 6 | 7 | Smart contract used to guard against potential reentrancy exploits. 8 | 9 | *Contract module that helps prevent reentrant calls to a function. Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier available, which can be applied to functions to make sure there are no nested (reentrant) calls to them. Note that because there is a single `nonReentrant` guard, functions marked as `nonReentrant` may not call one another. This can be worked around by making those functions `private`, and then adding `external` `nonReentrant` entry points to them. TIP: If you would like to learn more about reentrancy and alternative ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].* 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/RMRK/utils/IERC20.md: -------------------------------------------------------------------------------- 1 | # IERC20 2 | 3 | 4 | 5 | > IERC20 6 | 7 | Interface smart contract of the ERC20 smart contract implementation. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### allowance 14 | 15 | ```solidity 16 | function allowance(address owner, address spender) external view returns (uint256) 17 | ``` 18 | 19 | Used to grant permission to an account to spend the tokens of another 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | owner | address | Address that owns the tokens | 28 | | spender | address | Address that is being granted the permission to spend the tokens of the `owner` | 29 | 30 | #### Returns 31 | 32 | | Name | Type | Description | 33 | |---|---|---| 34 | | _0 | uint256 | Amount of tokens that the `spender` can manage | 35 | 36 | ### transfer 37 | 38 | ```solidity 39 | function transfer(address to, uint256 amount) external nonpayable returns (bool success) 40 | ``` 41 | 42 | Used to transfer tokens from the caller's account to another. 43 | 44 | 45 | 46 | #### Parameters 47 | 48 | | Name | Type | Description | 49 | |---|---|---| 50 | | to | address | Address of the account to which the tokens are being transferred | 51 | | amount | uint256 | Amount of tokens that are being transferred | 52 | 53 | #### Returns 54 | 55 | | Name | Type | Description | 56 | |---|---|---| 57 | | success | bool | A boolean value signifying whether the transfer was succesful (`true`) or not (`false`) | 58 | 59 | ### transferFrom 60 | 61 | ```solidity 62 | function transferFrom(address from, address to, uint256 amount) external nonpayable returns (bool success) 63 | ``` 64 | 65 | Used to transfer tokens from one address to another. 66 | 67 | 68 | 69 | #### Parameters 70 | 71 | | Name | Type | Description | 72 | |---|---|---| 73 | | from | address | Address of the account from which the the tokens are being transferred | 74 | | to | address | Address of the account to which the tokens are being transferred | 75 | | amount | uint256 | Amount of tokens that are being transferred | 76 | 77 | #### Returns 78 | 79 | | Name | Type | Description | 80 | |---|---|---| 81 | | success | bool | A boolean value signifying whether the transfer was succesful (`true`) or not (`false`) | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/RMRK/utils/IRMRKCollectionData.md: -------------------------------------------------------------------------------- 1 | # IRMRKCollectionData 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### collectionMetadata 14 | 15 | ```solidity 16 | function collectionMetadata() external view returns (string) 17 | ``` 18 | 19 | 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | string | undefined | 29 | 30 | ### contractURI 31 | 32 | ```solidity 33 | function contractURI() external view returns (string) 34 | ``` 35 | 36 | 37 | 38 | 39 | 40 | 41 | #### Returns 42 | 43 | | Name | Type | Description | 44 | |---|---|---| 45 | | _0 | string | undefined | 46 | 47 | ### getRoyaltyPercentage 48 | 49 | ```solidity 50 | function getRoyaltyPercentage() external view returns (uint256) 51 | ``` 52 | 53 | 54 | 55 | 56 | 57 | 58 | #### Returns 59 | 60 | | Name | Type | Description | 61 | |---|---|---| 62 | | _0 | uint256 | undefined | 63 | 64 | ### getRoyaltyRecipient 65 | 66 | ```solidity 67 | function getRoyaltyRecipient() external view returns (address) 68 | ``` 69 | 70 | 71 | 72 | 73 | 74 | 75 | #### Returns 76 | 77 | | Name | Type | Description | 78 | |---|---|---| 79 | | _0 | address | undefined | 80 | 81 | ### maxSupply 82 | 83 | ```solidity 84 | function maxSupply() external view returns (uint256) 85 | ``` 86 | 87 | 88 | 89 | 90 | 91 | 92 | #### Returns 93 | 94 | | Name | Type | Description | 95 | |---|---|---| 96 | | _0 | uint256 | undefined | 97 | 98 | ### name 99 | 100 | ```solidity 101 | function name() external view returns (string) 102 | ``` 103 | 104 | 105 | 106 | 107 | 108 | 109 | #### Returns 110 | 111 | | Name | Type | Description | 112 | |---|---|---| 113 | | _0 | string | undefined | 114 | 115 | ### owner 116 | 117 | ```solidity 118 | function owner() external view returns (address) 119 | ``` 120 | 121 | 122 | 123 | 124 | 125 | 126 | #### Returns 127 | 128 | | Name | Type | Description | 129 | |---|---|---| 130 | | _0 | address | undefined | 131 | 132 | ### symbol 133 | 134 | ```solidity 135 | function symbol() external view returns (string) 136 | ``` 137 | 138 | 139 | 140 | 141 | 142 | 143 | #### Returns 144 | 145 | | Name | Type | Description | 146 | |---|---|---| 147 | | _0 | string | undefined | 148 | 149 | ### totalSupply 150 | 151 | ```solidity 152 | function totalSupply() external view returns (uint256) 153 | ``` 154 | 155 | 156 | 157 | 158 | 159 | 160 | #### Returns 161 | 162 | | Name | Type | Description | 163 | |---|---|---| 164 | | _0 | uint256 | undefined | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /docs/RMRK/utils/RMRKBulkWriter.md: -------------------------------------------------------------------------------- 1 | # RMRKBulkWriter 2 | 3 | *RMRK team* 4 | 5 | > RMRKBulkWriter 6 | 7 | Smart contract of the RMRK Bulk Writer module. 8 | 9 | *Extra utility functions for RMRK contracts.* 10 | 11 | ## Methods 12 | 13 | ### bulkEquip 14 | 15 | ```solidity 16 | function bulkEquip(address collection, uint256 tokenId, RMRKBulkWriter.IntakeUnequip[] unequips, IERC6220.IntakeEquip[] equips) external nonpayable 17 | ``` 18 | 19 | 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | collection | address | undefined | 28 | | tokenId | uint256 | undefined | 29 | | unequips | RMRKBulkWriter.IntakeUnequip[] | undefined | 30 | | equips | IERC6220.IntakeEquip[] | undefined | 31 | 32 | ### bulkTransferAllChildren 33 | 34 | ```solidity 35 | function bulkTransferAllChildren(address collection, uint256 tokenId, address to, uint256 destinationId) external nonpayable 36 | ``` 37 | 38 | Transfers all children from one token. 39 | 40 | *If `destinationId` is 0, the destination can be an EoA or a contract implementing the IERC721Receiver interface.If `destinationId` is not 0, the destination must be a contract implementing the IERC7401 interface.This methods works with active children only.This contract must have approval to manage the NFT, only the current owner can call this method (not an approved operator).* 41 | 42 | #### Parameters 43 | 44 | | Name | Type | Description | 45 | |---|---|---| 46 | | collection | address | Address of the collection that this contract is managing | 47 | | tokenId | uint256 | ID of the token we are managing | 48 | | to | address | Address of the destination token or contract | 49 | | destinationId | uint256 | ID of the destination token | 50 | 51 | ### bulkTransferChildren 52 | 53 | ```solidity 54 | function bulkTransferChildren(address collection, uint256 tokenId, uint256[] childrenIndexes, address to, uint256 destinationId) external nonpayable 55 | ``` 56 | 57 | Transfers multiple children from one token. 58 | 59 | *If `destinationId` is 0, the destination can be an EoA or a contract implementing the IERC721Receiver interface.If `destinationId` is not 0, the destination must be a contract implementing the IERC7401 interface.`childrenIndexes` MUST be in ascending order, this method will transfer the children in reverse order to avoid index changes on children.This methods works with active children only.This contract must have approval to manage the NFT, only the current owner can call this method (not an approved operator).* 60 | 61 | #### Parameters 62 | 63 | | Name | Type | Description | 64 | |---|---|---| 65 | | collection | address | Address of the collection that this contract is managing | 66 | | tokenId | uint256 | ID of the token we are managing | 67 | | childrenIndexes | uint256[] | An array of indexes of the children to transfer | 68 | | to | address | Address of the destination token or contract | 69 | | destinationId | uint256 | ID of the destination token | 70 | 71 | ### replaceEquip 72 | 73 | ```solidity 74 | function replaceEquip(address collection, IERC6220.IntakeEquip data) external nonpayable 75 | ``` 76 | 77 | 78 | 79 | 80 | 81 | #### Parameters 82 | 83 | | Name | Type | Description | 84 | |---|---|---| 85 | | collection | address | undefined | 86 | | data | IERC6220.IntakeEquip | undefined | 87 | 88 | 89 | 90 | 91 | ## Errors 92 | 93 | ### RMRKCanOnlyDoBulkOperationsOnOwnedTokens 94 | 95 | ```solidity 96 | error RMRKCanOnlyDoBulkOperationsOnOwnedTokens() 97 | ``` 98 | 99 | Attempting to do a bulk operation on a token that is not owned by the caller 100 | 101 | 102 | 103 | 104 | ### RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime 105 | 106 | ```solidity 107 | error RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime() 108 | ``` 109 | 110 | Attempting to do a bulk operation with multiple tokens at a time 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /docs/RMRK/utils/RMRKBulkWriterPerCollection.md: -------------------------------------------------------------------------------- 1 | # RMRKBulkWriterPerCollection 2 | 3 | *RMRK team* 4 | 5 | > RMRKBulkWriterPerCollection 6 | 7 | Smart contract of the RMRK Bulk Writer per collection module. 8 | 9 | *Extra utility functions for RMRK contracts.* 10 | 11 | ## Methods 12 | 13 | ### bulkEquip 14 | 15 | ```solidity 16 | function bulkEquip(uint256 tokenId, RMRKBulkWriterPerCollection.IntakeUnequip[] unequips, IERC6220.IntakeEquip[] equips) external nonpayable 17 | ``` 18 | 19 | 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | undefined | 28 | | unequips | RMRKBulkWriterPerCollection.IntakeUnequip[] | undefined | 29 | | equips | IERC6220.IntakeEquip[] | undefined | 30 | 31 | ### getCollection 32 | 33 | ```solidity 34 | function getCollection() external view returns (address collection) 35 | ``` 36 | 37 | Returns the address of the collection that this contract is managing 38 | 39 | 40 | 41 | 42 | #### Returns 43 | 44 | | Name | Type | Description | 45 | |---|---|---| 46 | | collection | address | Address of the collection that this contract is managing | 47 | 48 | ### replaceEquip 49 | 50 | ```solidity 51 | function replaceEquip(IERC6220.IntakeEquip data) external nonpayable 52 | ``` 53 | 54 | 55 | 56 | 57 | 58 | #### Parameters 59 | 60 | | Name | Type | Description | 61 | |---|---|---| 62 | | data | IERC6220.IntakeEquip | undefined | 63 | 64 | 65 | 66 | 67 | ## Errors 68 | 69 | ### RMRKCanOnlyDoBulkOperationsOnOwnedTokens 70 | 71 | ```solidity 72 | error RMRKCanOnlyDoBulkOperationsOnOwnedTokens() 73 | ``` 74 | 75 | 76 | 77 | 78 | 79 | 80 | ### RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime 81 | 82 | ```solidity 83 | error RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime() 84 | ``` 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/RMRK/utils/RMRKRenderUtils.md: -------------------------------------------------------------------------------- 1 | # RMRKRenderUtils 2 | 3 | *RMRK team* 4 | 5 | > RMRKRenderUtils 6 | 7 | Smart contract of the RMRK render utils module. 8 | 9 | *Extra utility functions for RMRK contracts.* 10 | 11 | ## Methods 12 | 13 | ### getExtendedNft 14 | 15 | ```solidity 16 | function getExtendedNft(uint256 tokenId, address targetCollection) external view returns (struct RMRKRenderUtils.ExtendedNft data) 17 | ``` 18 | 19 | Used to get extended information about a specified token. 20 | 21 | *The full `ExtendedNft` struct looks like this: [ tokenMetadataUri, directOwner, rootOwner, activeAssetCount, pendingAssetCount priorities, maxSupply, totalSupply, issuer, name, symbol, activeChildrenNumber, pendingChildrenNumber, isSoulbound, hasMultiAssetInterface, hasNestingInterface, hasEquippableInterface ]* 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the token for which to retireve the `ExtendedNft` struct | 28 | | targetCollection | address | Address of the collection to which the specified token belongs to | 29 | 30 | #### Returns 31 | 32 | | Name | Type | Description | 33 | |---|---|---| 34 | | data | RMRKRenderUtils.ExtendedNft | The `ExtendedNft` struct containing the specified token's data | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/console.md: -------------------------------------------------------------------------------- 1 | # console 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/implementations/catalog/RMRKCatalogFactory.md: -------------------------------------------------------------------------------- 1 | # RMRKCatalogFactory 2 | 3 | *RMRK team* 4 | 5 | > RMRKCatalogFactory 6 | 7 | Smart contract to deploy catalog implementations and keep track of deployers. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### deployCatalog 14 | 15 | ```solidity 16 | function deployCatalog(string metadataURI, string type_) external nonpayable returns (address) 17 | ``` 18 | 19 | Used to deploy a new RMRKCatalog implementation. 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | metadataURI | string | Base metadata URI of the catalog | 28 | | type_ | string | The type of the catalog | 29 | 30 | #### Returns 31 | 32 | | Name | Type | Description | 33 | |---|---|---| 34 | | _0 | address | The address of the deployed catalog | 35 | 36 | ### getDeployerCatalogAtIndex 37 | 38 | ```solidity 39 | function getDeployerCatalogAtIndex(address deployer, uint256 index) external view returns (address catalogAddress) 40 | ``` 41 | 42 | Used to get a catalog deployed by a given deployer at a given index. 43 | 44 | 45 | 46 | #### Parameters 47 | 48 | | Name | Type | Description | 49 | |---|---|---| 50 | | deployer | address | The address of the deployer | 51 | | index | uint256 | The index of the catalog | 52 | 53 | #### Returns 54 | 55 | | Name | Type | Description | 56 | |---|---|---| 57 | | catalogAddress | address | The address of the catalog | 58 | 59 | ### getDeployerCatalogs 60 | 61 | ```solidity 62 | function getDeployerCatalogs(address deployer) external view returns (address[]) 63 | ``` 64 | 65 | Used to get all catalogs deployed by a given deployer. 66 | 67 | 68 | 69 | #### Parameters 70 | 71 | | Name | Type | Description | 72 | |---|---|---| 73 | | deployer | address | The address of the deployer | 74 | 75 | #### Returns 76 | 77 | | Name | Type | Description | 78 | |---|---|---| 79 | | _0 | address[] | An array of addresses of the catalogs deployed by the deployer | 80 | 81 | ### getLastDeployerCatalog 82 | 83 | ```solidity 84 | function getLastDeployerCatalog(address deployer) external view returns (address catalogAddress) 85 | ``` 86 | 87 | Used to get the last catalog deployed by a given deployer. 88 | 89 | 90 | 91 | #### Parameters 92 | 93 | | Name | Type | Description | 94 | |---|---|---| 95 | | deployer | address | The address of the deployer | 96 | 97 | #### Returns 98 | 99 | | Name | Type | Description | 100 | |---|---|---| 101 | | catalogAddress | address | The address of the last catalog deployed by the deployer | 102 | 103 | ### getTotalDeployerCatalogs 104 | 105 | ```solidity 106 | function getTotalDeployerCatalogs(address deployer) external view returns (uint256 total) 107 | ``` 108 | 109 | Used to get the total number of catalogs deployed by a given deployer. 110 | 111 | 112 | 113 | #### Parameters 114 | 115 | | Name | Type | Description | 116 | |---|---|---| 117 | | deployer | address | The address of the deployer | 118 | 119 | #### Returns 120 | 121 | | Name | Type | Description | 122 | |---|---|---| 123 | | total | uint256 | The total number of catalogs deployed by the deployer | 124 | 125 | 126 | 127 | ## Events 128 | 129 | ### CatalogDeployed 130 | 131 | ```solidity 132 | event CatalogDeployed(address indexed deployer, address indexed catalog) 133 | ``` 134 | 135 | 136 | 137 | 138 | 139 | #### Parameters 140 | 141 | | Name | Type | Description | 142 | |---|---|---| 143 | | deployer `indexed` | address | undefined | 144 | | catalog `indexed` | address | undefined | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/implementations/lazyMintErc20/InitDataERC20Pay.md: -------------------------------------------------------------------------------- 1 | # InitDataERC20Pay 2 | 3 | *RMRK team* 4 | 5 | > InitDataERC20Pay 6 | 7 | Interface representation of RMRK initialization data. 8 | 9 | *This interface provides a struct used to pack data to avoid stack too deep error for too many arguments.* 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/implementations/lazyMintNative/InitDataNativePay.md: -------------------------------------------------------------------------------- 1 | # InitDataNativePay 2 | 3 | *RMRK team* 4 | 5 | > InitDataNativePay 6 | 7 | Interface representation of RMRK initialization data. 8 | 9 | *This interface provides a struct used to pack data to avoid stack too deep error for too many arguments.* 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/implementations/utils/RMRKRoyaltiesSplitter.md: -------------------------------------------------------------------------------- 1 | # RMRKRoyaltiesSplitter 2 | 3 | *RMRK team* 4 | 5 | > RMRKRoyaltiesSplitter 6 | 7 | Smart contract of the RMRK Royalties Spliter module. 8 | 9 | *This smart contract provides a simple way to share royalties from either native or erc20 payments.* 10 | 11 | ## Methods 12 | 13 | ### MAX_BPS 14 | 15 | ```solidity 16 | function MAX_BPS() external view returns (uint256) 17 | ``` 18 | 19 | 20 | 21 | 22 | 23 | 24 | #### Returns 25 | 26 | | Name | Type | Description | 27 | |---|---|---| 28 | | _0 | uint256 | undefined | 29 | 30 | ### distributeERC20 31 | 32 | ```solidity 33 | function distributeERC20(address currency, uint256 amount) external nonpayable 34 | ``` 35 | 36 | Distributes an ERC20 payment to the beneficiaries. 37 | 38 | *The payment is distributed according to the shares specified in the constructor.* 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | |---|---|---| 44 | | currency | address | The address of the ERC20 token. | 45 | | amount | uint256 | The amount of tokens to distribute. | 46 | 47 | ### getBenefiariesAndShares 48 | 49 | ```solidity 50 | function getBenefiariesAndShares() external view returns (address[] beneficiaries, uint256[] shares) 51 | ``` 52 | 53 | Returns the list of beneficiaries and their shares. 54 | 55 | 56 | 57 | 58 | #### Returns 59 | 60 | | Name | Type | Description | 61 | |---|---|---| 62 | | beneficiaries | address[] | The list of beneficiaries. | 63 | | shares | uint256[] | The list of shares. | 64 | 65 | 66 | 67 | ## Events 68 | 69 | ### ERCPaymentDistributed 70 | 71 | ```solidity 72 | event ERCPaymentDistributed(address indexed sender, address indexed currency, uint256 amount) 73 | ``` 74 | 75 | 76 | 77 | 78 | 79 | #### Parameters 80 | 81 | | Name | Type | Description | 82 | |---|---|---| 83 | | sender `indexed` | address | undefined | 84 | | currency `indexed` | address | undefined | 85 | | amount | uint256 | undefined | 86 | 87 | ### NativePaymentDistributed 88 | 89 | ```solidity 90 | event NativePaymentDistributed(address indexed sender, uint256 amount) 91 | ``` 92 | 93 | 94 | 95 | 96 | 97 | #### Parameters 98 | 99 | | Name | Type | Description | 100 | |---|---|---| 101 | | sender `indexed` | address | undefined | 102 | | amount | uint256 | undefined | 103 | 104 | 105 | 106 | ## Errors 107 | 108 | ### FailedToSend 109 | 110 | ```solidity 111 | error FailedToSend() 112 | ``` 113 | 114 | 115 | 116 | 117 | 118 | 119 | ### InvalidInput 120 | 121 | ```solidity 122 | error InvalidInput() 123 | ``` 124 | 125 | 126 | 127 | 128 | 129 | 130 | ### OnlyBeneficiary 131 | 132 | ```solidity 133 | error OnlyBeneficiary() 134 | ``` 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /docs/implementations/utils/RMRKTokenURIEnumerated.md: -------------------------------------------------------------------------------- 1 | # RMRKTokenURIEnumerated 2 | 3 | *RMRK team* 4 | 5 | > RMRKTokenURIEnumerated 6 | 7 | Implementation of enumerable token URI. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### tokenURI 14 | 15 | ```solidity 16 | function tokenURI(uint256 tokenId) external view returns (string tokenURI_) 17 | ``` 18 | 19 | Used to retrieve the metadata URI of a token. 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the token to retrieve the metadata URI for | 28 | 29 | #### Returns 30 | 31 | | Name | Type | Description | 32 | |---|---|---| 33 | | tokenURI_ | string | Metadata URI of the specified token | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/implementations/utils/RMRKTokenURIPerToken.md: -------------------------------------------------------------------------------- 1 | # RMRKTokenURIPerToken 2 | 3 | *RMRK team* 4 | 5 | > RMRKTokenURIPerToken 6 | 7 | Implementation of token URI per token. 8 | 9 | 10 | 11 | ## Methods 12 | 13 | ### tokenURI 14 | 15 | ```solidity 16 | function tokenURI(uint256 tokenId) external view returns (string tokenURI_) 17 | ``` 18 | 19 | Used to retrieve the metadata URI of a token. 20 | 21 | 22 | 23 | #### Parameters 24 | 25 | | Name | Type | Description | 26 | |---|---|---| 27 | | tokenId | uint256 | ID of the token to retrieve the metadata URI for | 28 | 29 | #### Returns 30 | 31 | | Name | Type | Description | 32 | |---|---|---| 33 | | tokenURI_ | string | Metadata URI of the specified token | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x2b6c413a5b076f917ada28ac44b0995daee75f06678705d1eb75ff5da38bdd3b" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /img/General_Overview_Modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmrk-team/evm/d10218a74558ae53c31adc178af73dc59cbc7fa0/img/General_Overview_Modules.png -------------------------------------------------------------------------------- /mythril-remappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "remappings": ["@openzeppelin/=./node_modules/@openzeppelin/"] 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rmrk-team/evm-contracts", 3 | "version": "2.5.3", 4 | "license": "Apache-2.0", 5 | "files": [ 6 | "contracts/RMRK/*", 7 | "contracts/implementations/*" 8 | ], 9 | "scripts": { 10 | "test": "hardhat typechain && hardhat test", 11 | "coverage": "hardhat typechain && NODE_OPTIONS='--max-old-space-size=8192' hardhat coverage", 12 | "typechain": "hardhat typechain", 13 | "prettier": "prettier --write .", 14 | "prepare:commit": "hardhat dodoc && prettier --write ." 15 | }, 16 | "engines": { 17 | "node": ">=18" 18 | }, 19 | "dependencies": { 20 | "@openzeppelin/contracts": "^5.0.2" 21 | }, 22 | "devDependencies": { 23 | "@nomicfoundation/hardhat-chai-matchers": "^2.0.3", 24 | "@nomicfoundation/hardhat-ethers": "^3.0.5", 25 | "@nomicfoundation/hardhat-network-helpers": "^1.0.10", 26 | "@nomicfoundation/hardhat-toolbox": "^4.0.0", 27 | "@nomicfoundation/hardhat-verify": "^2.0.3", 28 | "@primitivefi/hardhat-dodoc": "^0.2.3", 29 | "@typechain/ethers-v6": "^0.5.1", 30 | "@typechain/hardhat": "^9.1.0", 31 | "@types/chai": "^4.3.11", 32 | "@types/mocha": "^10.0.6", 33 | "@types/node": "^20.11.7", 34 | "@typescript-eslint/eslint-plugin": "^6.19.1", 35 | "@typescript-eslint/parser": "^6.19.1", 36 | "chai": "^4.4.1", 37 | "dotenv": "^16.4.1", 38 | "eslint": "^8.56.0", 39 | "eslint-config-prettier": "^9.1.0", 40 | "eslint-config-standard": "^17.1.0", 41 | "eslint-import-resolver-typescript": "^3.6.1", 42 | "eslint-plugin-import": "^2.29.1", 43 | "eslint-plugin-n": "^16.6.2", 44 | "eslint-plugin-prettier": "^5.1.3", 45 | "eslint-plugin-promise": "^6.1.1", 46 | "ethers": "^6.10.0", 47 | "hardhat": "^2.19.4", 48 | "hardhat-contract-sizer": "^2.10.0", 49 | "hardhat-gas-reporter": "^1.0.9", 50 | "prettier": "^3.2.4", 51 | "prettier-plugin-solidity": "^1.3.1", 52 | "rimraf": "^5.0.5", 53 | "solc": "0.8.21", 54 | "solidity-coverage": "0.8.6-sha1.0", 55 | "squirrelly": "^9.0.0", 56 | "ts-node": "11.0.0-beta.1", 57 | "typechain": "^8.3.2", 58 | "typescript": "^5.3.3", 59 | "walk-sync": "^3.0.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /scripts/deploy-bulk-writer.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 2 | import { ethers, run } from 'hardhat'; 3 | import { sleep } from './utils'; 4 | 5 | async function main() { 6 | const accounts: SignerWithAddress[] = await ethers.getSigners(); 7 | const owner = accounts[0]; 8 | console.log(`Deployer address: ${owner.address}`); 9 | 10 | // We get the contract to deploy 11 | const factory = await ethers.getContractFactory('RMRKBulkWriter'); 12 | const bulkwriter = await factory.deploy(); 13 | await bulkwriter.waitForDeployment(); 14 | const bulkwriterAddress = await bulkwriter.getAddress(); 15 | 16 | console.log('RMRK Bulk Writer deployed to:', bulkwriterAddress); 17 | await sleep(1000); 18 | 19 | await run('verify:verify', { 20 | address: bulkwriterAddress, 21 | constructorArguments: [], 22 | }); 23 | } 24 | 25 | // We recommend this pattern to be able to use async/await everywhere 26 | // and properly handle errors. 27 | main().catch((error) => { 28 | console.error(error); 29 | process.exitCode = 1; 30 | }); 31 | -------------------------------------------------------------------------------- /scripts/deploy-catalog-factory.ts: -------------------------------------------------------------------------------- 1 | import { ethers, run } from 'hardhat'; 2 | import { sleep } from './utils'; 3 | 4 | async function main() { 5 | const catalogFactoryFactory = await ethers.getContractFactory('RMRKCatalogFactory'); 6 | const catalogFactory = await catalogFactoryFactory.deploy(); 7 | await catalogFactory.waitForDeployment(); 8 | console.log('RMRK Catalog Factory deployed to:', await catalogFactory.getAddress()); 9 | await sleep(1000); 10 | 11 | await run('verify:verify', { 12 | address: await catalogFactory.getAddress(), 13 | constructorArguments: [], 14 | }); 15 | } 16 | 17 | // We recommend this pattern to be able to use async/await everywhere 18 | // and properly handle errors. 19 | main().catch((error) => { 20 | console.error(error); 21 | process.exitCode = 1; 22 | }); 23 | -------------------------------------------------------------------------------- /scripts/deploy-catalog-utils.ts: -------------------------------------------------------------------------------- 1 | import { ethers, run } from 'hardhat'; 2 | import { sleep } from './utils'; 3 | 4 | async function main() { 5 | // We get the contract to deploy 6 | // // Send eth to this address:0xfbea1b97406c6945d07f50f588e54144ea8b684f 7 | // let tx = { 8 | // to: '0xfbea1b97406c6945d07f50f588e54144ea8b684f', 9 | // value: ethers.parseEther('0.03'), 10 | // nonce: 235, 11 | // }; 12 | // const [signer] = await ethers.getSigners(); 13 | // const txResponse = await signer.sendTransaction(tx); 14 | // await txResponse.wait(); 15 | // return; 16 | 17 | const catalogUtilsFactory = await ethers.getContractFactory('RMRKCatalogUtils'); 18 | const catalogUtils = await catalogUtilsFactory.deploy(); 19 | await catalogUtils.waitForDeployment(); 20 | console.log('RMRK Catalog Utils deployed to:', await catalogUtils.getAddress()); 21 | await sleep(1000); 22 | 23 | await run('verify:verify', { 24 | address: await catalogUtils.getAddress(), 25 | constructorArguments: [], 26 | }); 27 | } 28 | 29 | // We recommend this pattern to be able to use async/await everywhere 30 | // and properly handle errors. 31 | main().catch((error) => { 32 | console.error(error); 33 | process.exitCode = 1; 34 | }); 35 | -------------------------------------------------------------------------------- /scripts/deploy-collection-utils.ts: -------------------------------------------------------------------------------- 1 | import { ethers, run } from 'hardhat'; 2 | import { sleep } from './utils'; 3 | 4 | async function main() { 5 | // We get the contract to deploy 6 | const collectionUtilsFactory = await ethers.getContractFactory('RMRKCollectionUtils'); 7 | const collectionUtils = await collectionUtilsFactory.deploy(); 8 | await collectionUtils.waitForDeployment(); 9 | console.log('RMRK Collection Utils deployed to:', await collectionUtils.getAddress()); 10 | await sleep(1000); 11 | 12 | await run('verify:verify', { 13 | address: await collectionUtils.getAddress(), 14 | constructorArguments: [], 15 | }); 16 | } 17 | 18 | // We recommend this pattern to be able to use async/await everywhere 19 | // and properly handle errors. 20 | main().catch((error) => { 21 | console.error(error); 22 | process.exitCode = 1; 23 | }); 24 | -------------------------------------------------------------------------------- /scripts/deploy-emotable.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 2 | import { ethers, run } from 'hardhat'; 3 | import { sleep } from './utils'; 4 | 5 | async function main() { 6 | const accounts: SignerWithAddress[] = await ethers.getSigners(); 7 | const owner = accounts[0]; 8 | console.log(`Deployer address: ${owner.address}`); 9 | // We get the contract to deploy 10 | const emotableRepoFactory = await ethers.getContractFactory('RMRKEmotesRepository'); 11 | const emotableRepo = await emotableRepoFactory.deploy(); 12 | await emotableRepo.waitForDeployment(); 13 | console.log('RMRKEmotesRepository deployed to:', await emotableRepo.getAddress()); 14 | await sleep(1000); 15 | 16 | await run('verify:verify', { 17 | address: await emotableRepo.getAddress(), 18 | constructorArguments: [], 19 | }); 20 | } 21 | 22 | // We recommend this pattern to be able to use async/await everywhere 23 | // and properly handle errors. 24 | main().catch((error) => { 25 | console.error(error); 26 | process.exitCode = 1; 27 | }); 28 | -------------------------------------------------------------------------------- /scripts/deploy-render-utils.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 2 | import { ethers, run } from 'hardhat'; 3 | import { sleep } from './utils'; 4 | 5 | async function main() { 6 | const accounts: SignerWithAddress[] = await ethers.getSigners(); 7 | const owner = accounts[0]; 8 | console.log(`Deployer address: ${owner.address}`); 9 | 10 | // Calculate future address: 11 | const deployerNonce = await owner.getNonce(); 12 | const futureAddress = ethers.getCreateAddress({ from: owner.address, nonce: deployerNonce }); 13 | console.log(`Render utils will be deployed to: ${futureAddress}`); 14 | 15 | // We get the contract to deploy 16 | const renderUtilsFactory = await ethers.getContractFactory('RMRKEquipRenderUtils'); 17 | const renderUtils = await renderUtilsFactory.deploy(); 18 | await renderUtils.waitForDeployment(); 19 | 20 | console.log('RMRK Equip Render Utils deployed to:', await renderUtils.getAddress()); 21 | await sleep(1000); 22 | 23 | await run('verify:verify', { 24 | address: await renderUtils.getAddress(), 25 | constructorArguments: [], 26 | }); 27 | } 28 | 29 | // We recommend this pattern to be able to use async/await everywhere 30 | // and properly handle errors. 31 | main().catch((error) => { 32 | console.error(error); 33 | process.exitCode = 1; 34 | }); 35 | -------------------------------------------------------------------------------- /scripts/deploy-royalties-splitter.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 2 | import { ethers, run } from 'hardhat'; 3 | import { sleep } from './utils'; 4 | 5 | async function main() { 6 | const accounts: SignerWithAddress[] = await ethers.getSigners(); 7 | const owner = accounts[0]; 8 | console.log(`Deployer address: ${owner.address}`); 9 | // We get the contract to deploy 10 | 11 | const beneficiaries: string[] = []; // TODO: Set beneficiaries 12 | const sharesBPS: number[] = []; // TODO: Set sharesBPS 13 | 14 | const royaltiesSplitterFactory = await ethers.getContractFactory('RMRKRoyaltiesSplitter'); 15 | const royaltiesSplitter = await royaltiesSplitterFactory.deploy(beneficiaries, sharesBPS); 16 | await royaltiesSplitter.waitForDeployment(); 17 | console.log('RMRK Royalties Splitter deployed to:', await royaltiesSplitter.getAddress()); 18 | await sleep(10000); 19 | 20 | await run('verify:verify', { 21 | address: await royaltiesSplitter.getAddress(), 22 | constructorArguments: [], 23 | }); 24 | } 25 | 26 | // We recommend this pattern to be able to use async/await everywhere 27 | // and properly handle errors. 28 | main().catch((error) => { 29 | console.error(error); 30 | process.exitCode = 1; 31 | }); 32 | -------------------------------------------------------------------------------- /scripts/deploy-token-attributes-repo.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 2 | import { ethers, run } from 'hardhat'; 3 | import { sleep } from './utils'; 4 | 5 | async function main() { 6 | const accounts: SignerWithAddress[] = await ethers.getSigners(); 7 | const owner = accounts[0]; 8 | console.log(`Deployer address: ${owner.address}`); 9 | // We get the contract to deploy 10 | const tokenAttributesRepoFactory = await ethers.getContractFactory( 11 | 'RMRKTokenAttributesRepository', 12 | ); 13 | const tokenAttributesRepo = await tokenAttributesRepoFactory.deploy(); 14 | await tokenAttributesRepo.waitForDeployment(); 15 | console.log('RMRKTokenAttributesRepository deployed to:', await tokenAttributesRepo.getAddress()); 16 | await sleep(10000); 17 | 18 | await run('verify:verify', { 19 | address: await tokenAttributesRepo.getAddress(), 20 | constructorArguments: [], 21 | }); 22 | } 23 | 24 | // We recommend this pattern to be able to use async/await everywhere 25 | // and properly handle errors. 26 | main().catch((error) => { 27 | console.error(error); 28 | process.exitCode = 1; 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/generate-abis.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import walkSync from 'walk-sync'; 3 | import { rimraf } from 'rimraf'; 4 | 5 | const getTheAbi = () => { 6 | try { 7 | rimraf(`${process.cwd()}/artifacts/abis`).then(() => { 8 | const implementations = walkSync(`${process.cwd()}/artifacts/contracts/implementations`, { 9 | directories: false, 10 | }); 11 | 12 | const utils = walkSync(`${process.cwd()}/artifacts/contracts/RMRK/utils`, { 13 | directories: false, 14 | }); 15 | 16 | const dirExists = fs.existsSync(`${process.cwd()}/artifacts/abis/implementations`); 17 | if (!dirExists) { 18 | fs.mkdirSync(`${process.cwd()}/artifacts/abis`); 19 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations`); 20 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/abstract`); 21 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/lazyMintErc20`); 22 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/lazyMintNative`); 23 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/nativeTokenPay`); 24 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/erc20Pay`); 25 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/premint`); 26 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/implementations/utils`); 27 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/RMRK`); 28 | fs.mkdirSync(`${process.cwd()}/artifacts/abis/RMRK/utils`); 29 | } 30 | 31 | implementations.forEach((implementation) => { 32 | const filename = implementation.slice(0, implementation.indexOf('.sol')); 33 | const file = fs.readFileSync( 34 | `${process.cwd()}/artifacts/contracts/implementations/${implementation}`, 35 | 'utf8', 36 | ); 37 | const json = JSON.parse(file); 38 | 39 | if (json.abi) { 40 | fs.writeFileSync( 41 | `${process.cwd()}/artifacts/abis/implementations/${filename}.json`, 42 | JSON.stringify(json.abi), 43 | ); 44 | } 45 | }); 46 | 47 | utils.forEach((util) => { 48 | const filename = util.slice(0, util.indexOf('.sol')); 49 | const file = fs.readFileSync( 50 | `${process.cwd()}/artifacts/contracts/RMRK/utils/${util}`, 51 | 'utf8', 52 | ); 53 | const json = JSON.parse(file); 54 | 55 | if (json.abi) { 56 | fs.writeFileSync( 57 | `${process.cwd()}/artifacts/abis/RMRK/utils/${filename}.json`, 58 | JSON.stringify(json.abi), 59 | ); 60 | } 61 | }); 62 | }); 63 | } catch (e) { 64 | console.log(`e`, e); 65 | } 66 | }; 67 | 68 | getTheAbi(); 69 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | export const sleep = (ms: number): Promise => { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(), ms); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /test/behavior/metadata.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat'; 2 | import { expect } from 'chai'; 3 | import { Contract } from 'ethers'; 4 | 5 | async function shouldHaveMetadata( 6 | mint: (token: Contract, to: string) => Promise, 7 | isTokenUriEnumerated: boolean, 8 | ): Promise { 9 | it('can get tokenURI', async function () { 10 | const owner = (await ethers.getSigners())[0]; 11 | const tokenId = await mint(this.token, owner.address); 12 | if (isTokenUriEnumerated) { 13 | expect(await this.token.tokenURI(tokenId)).to.eql(`ipfs://tokenURI/${tokenId}`); 14 | } else { 15 | expect(await this.token.tokenURI(tokenId)).to.eql('ipfs://tokenURI'); 16 | } 17 | }); 18 | 19 | it('can get collection meta', async function () { 20 | expect(await this.token.contractURI()).to.eql('ipfs://collection-meta'); 21 | }); 22 | } 23 | 24 | export default shouldHaveMetadata; 25 | -------------------------------------------------------------------------------- /test/behavior/mintingImpl.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat'; 2 | import { expect } from 'chai'; 3 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 4 | import { ONE_ETH } from '../utils'; 5 | 6 | async function shouldControlValidMinting(): Promise { 7 | let addrs: SignerWithAddress[]; 8 | 9 | beforeEach(async function () { 10 | const [, ...signersAddr] = await ethers.getSigners(); 11 | addrs = signersAddr; 12 | }); 13 | 14 | it('cannot mint under price', async function () { 15 | const HALF_ETH = ONE_ETH / 2n; 16 | await expect( 17 | this.token.mint(addrs[0].address, 1, { value: HALF_ETH }), 18 | ).to.be.revertedWithCustomError(this.token, 'RMRKWrongValueSent'); 19 | }); 20 | 21 | it('cannot mint 0 units', async function () { 22 | await expect( 23 | this.token.mint(addrs[0].address, 0, { value: ONE_ETH }), 24 | ).to.be.revertedWithCustomError(this.token, 'RMRKMintZero'); 25 | }); 26 | 27 | it('cannot mint over max supply', async function () { 28 | await expect( 29 | this.token.mint(addrs[0].address, 99999, { value: ONE_ETH }), 30 | ).to.be.revertedWithCustomError(this.token, 'RMRKMintOverMax'); 31 | }); 32 | } 33 | 34 | export default shouldControlValidMinting; 35 | -------------------------------------------------------------------------------- /test/behavior/ownableLock.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { ethers } from 'hardhat'; 3 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 4 | import { OwnableLockMock } from '../../typechain-types'; 5 | 6 | async function shouldBehaveOwnableLock(ismock: boolean) { 7 | let ownableLock: OwnableLockMock; 8 | 9 | let owner: SignerWithAddress; 10 | let addrs: SignerWithAddress[]; 11 | 12 | beforeEach(async function () { 13 | const [signersOwner, ...signersAddr] = await ethers.getSigners(); 14 | owner = signersOwner; 15 | addrs = signersAddr; 16 | 17 | ownableLock = this.token; 18 | }); 19 | 20 | describe('Init', async function () { 21 | it('can get owner', async function () { 22 | expect(await ownableLock.owner()).to.equal(owner.address); 23 | }); 24 | 25 | it('emits LockSet event when the lock is set', async function () { 26 | await expect(ownableLock.connect(owner).setLock()).to.emit(ownableLock, 'LockSet'); 27 | }); 28 | 29 | it('can get lock', async function () { 30 | expect(await ownableLock.getLock()).to.equal(false); 31 | await ownableLock.connect(owner).setLock(); 32 | expect(await ownableLock.getLock()).to.equal(true); 33 | // Test second call of setLock 34 | await ownableLock.connect(owner).setLock(); 35 | expect(await ownableLock.getLock()).to.equal(true); 36 | }); 37 | 38 | it('reverts if setLock caller is not owner', async function () { 39 | await expect(ownableLock.connect(addrs[0]).setLock()).to.be.revertedWithCustomError( 40 | ownableLock, 41 | 'RMRKNotOwner', 42 | ); 43 | }); 44 | 45 | if (ismock) { 46 | it('fail when locked', async function () { 47 | expect(await ownableLock.testLock()).to.equal(true); 48 | await ownableLock.connect(owner).setLock(); 49 | await expect(ownableLock.connect(owner).testLock()).to.be.revertedWithCustomError( 50 | ownableLock, 51 | 'RMRKLocked', 52 | ); 53 | }); 54 | } 55 | }); 56 | } 57 | 58 | export default shouldBehaveOwnableLock; 59 | -------------------------------------------------------------------------------- /test/behavior/royalties.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat'; 2 | import { expect } from 'chai'; 3 | import { Contract } from 'ethers'; 4 | import { ADDRESS_ZERO, bn, ONE_ETH } from '../utils'; 5 | 6 | async function shouldHaveRoyalties( 7 | mint: (token: Contract, to: string) => Promise, 8 | ): Promise { 9 | it('can get royalty data', async function () { 10 | const owner = (await ethers.getSigners())[0]; 11 | const tokenId = await mint(this.token, owner.address); 12 | expect(await this.token.royaltyInfo(tokenId, ONE_ETH * 10n)).to.eql([ADDRESS_ZERO, ONE_ETH]); 13 | }); 14 | 15 | it('can get royalty receipient and % in basis points', async function () { 16 | // These 2 values are used on all implementation deploys: 17 | expect(await this.token.getRoyaltyRecipient()).to.eql(ADDRESS_ZERO); 18 | expect(await this.token.getRoyaltyPercentage()).to.eql(bn(1000)); 19 | }); 20 | 21 | it('can get and update royalty receipient', async function () { 22 | const newRecipient = (await ethers.getSigners())[5]; 23 | await this.token.updateRoyaltyRecipient(await newRecipient.getAddress()); 24 | expect(await this.token.getRoyaltyRecipient()).to.eql(await newRecipient.getAddress()); 25 | }); 26 | 27 | it('cannot update royalty receipient if not owner', async function () { 28 | const newRecipient = (await ethers.getSigners())[5]; 29 | await expect( 30 | this.token.connect(newRecipient).updateRoyaltyRecipient(await newRecipient.getAddress()), 31 | ).to.be.revertedWithCustomError(this.token, 'RMRKNotOwner'); 32 | }); 33 | } 34 | 35 | export default shouldHaveRoyalties; 36 | -------------------------------------------------------------------------------- /test/implementations/catalogFactory.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat'; 2 | import { expect } from 'chai'; 3 | import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; 4 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 5 | import { RMRKCatalogFactory } from '../../typechain-types'; 6 | 7 | async function catalogFactoryFixture(): Promise { 8 | const factory = await ethers.getContractFactory('RMRKCatalogFactory'); 9 | const catalogFactory = await factory.deploy(); 10 | await catalogFactory.waitForDeployment(); 11 | 12 | return catalogFactory; 13 | } 14 | 15 | describe('CatalogImpl', async () => { 16 | let catalogFactory: RMRKCatalogFactory; 17 | let deployer1: SignerWithAddress; 18 | let deployer2: SignerWithAddress; 19 | 20 | beforeEach(async () => { 21 | [, deployer1, deployer2] = await ethers.getSigners(); 22 | catalogFactory = await loadFixture(catalogFactoryFixture); 23 | }); 24 | 25 | it('can deploy a new catalog', async () => { 26 | const tx = await catalogFactory 27 | .connect(deployer1) 28 | .deployCatalog('ipfs://catalogMetadata', 'img/jpeg'); 29 | const receipt = await tx.wait(); 30 | const catalogAddress = receipt?.logs?.[0]?.address; 31 | if (!catalogAddress) { 32 | throw new Error('Catalog address not found'); 33 | } 34 | const catalog = await ethers.getContractAt('RMRKCatalogImpl', catalogAddress); 35 | const metadataURI = await catalog.getMetadataURI(); 36 | const mediaType = await catalog.getType(); 37 | 38 | expect(metadataURI).to.equal('ipfs://catalogMetadata'); 39 | expect(mediaType).to.equal('img/jpeg'); 40 | }); 41 | 42 | it('can get catalogs deployed by a deployer', async () => { 43 | const catalogAddress1 = await deployAndGetAddress( 44 | deployer1, 45 | 'ipfs://catalogMetadata1', 46 | 'img/jpeg', 47 | ); 48 | const catalogAddress2 = await deployAndGetAddress( 49 | deployer1, 50 | 'ipfs://catalogMetadata2', 51 | 'img/png', 52 | ); 53 | const catalogAddress3 = await deployAndGetAddress( 54 | deployer2, 55 | 'ipfs://otherDeployerCatalog', 56 | 'img/svg', 57 | ); 58 | 59 | expect(await catalogFactory.getDeployerCatalogs(deployer1.address)).to.deep.equal([ 60 | catalogAddress1, 61 | catalogAddress2, 62 | ]); 63 | expect(await catalogFactory.getDeployerCatalogs(deployer2.address)).to.deep.equal([ 64 | catalogAddress3, 65 | ]); 66 | 67 | expect(await catalogFactory.getLastDeployerCatalog(deployer1.address)).to.equal( 68 | catalogAddress2, 69 | ); 70 | expect(await catalogFactory.getLastDeployerCatalog(deployer2.address)).to.equal( 71 | catalogAddress3, 72 | ); 73 | 74 | expect(await catalogFactory.getTotalDeployerCatalogs(deployer1.address)).to.equal(2); 75 | expect(await catalogFactory.getTotalDeployerCatalogs(deployer2.address)).to.equal(1); 76 | 77 | expect(await catalogFactory.getDeployerCatalogAtIndex(deployer1.address, 0)).to.equal( 78 | catalogAddress1, 79 | ); 80 | expect(await catalogFactory.getDeployerCatalogAtIndex(deployer1.address, 1)).to.equal( 81 | catalogAddress2, 82 | ); 83 | }); 84 | 85 | async function deployAndGetAddress( 86 | deployer: SignerWithAddress, 87 | metadataURI: string, 88 | mediaType: string, 89 | ) { 90 | const tx = await catalogFactory.connect(deployer).deployCatalog(metadataURI, mediaType); 91 | const receipt = await tx.wait(); 92 | const catalogAddress = receipt?.logs?.[0]?.address; 93 | if (!catalogAddress) { 94 | throw new Error('Catalog address not found'); 95 | } 96 | return catalogAddress; 97 | } 98 | }); 99 | -------------------------------------------------------------------------------- /test/interfaces.ts: -------------------------------------------------------------------------------- 1 | export const IERC165 = '0x01ffc9a7'; 2 | export const IERC721 = '0x80ac58cd'; 3 | export const IERC721Metadata = '0x5b5e139f'; 4 | export const IERC2981 = '0x2a55205a'; // Royalties 5 | export const IERC5773 = '0x06b4329a'; // MultiAsset 6 | export const IERC6220 = '0x28bc9ae4'; // Equippable and Composable 7 | export const IERC6454 = '0x91a6262f'; // Soulbound 8 | export const IERC7401 = '0x42b0e56f'; // Nestable 9 | export const IERC7409 = '0x1b3327ab'; // Emotes Repository 10 | export const IERC7508 = '0x212206a8'; // Attributes Repository 11 | export const IERC7590 = '0x6f87c75c'; // ERC20 Token Holder 12 | export const IOtherInterface = '0xffffffff'; 13 | export const IRMRKCatalog = '0xd912401f'; // ERC6220 14 | export const IRMRKCatalogExtended = '0xbe1dfb42'; 15 | export const IRMRKImplementation = '0x524D524B'; // "RMRK" in ASCII hex 16 | export const IRMRKMultiAssetAutoIndex = '0x1cf132fe'; 17 | export const IRMRKNestableAutoIndex = '0x1884d52d'; 18 | export const IRMRKReclaimableChild = '0x2fb59acf'; 19 | export const IRMRKRevealable = '0x4be9cc42'; 20 | export const IRMRKRevealer = '0xf9296b16'; 21 | export const IRMRKTypedMultiAsset = '0x7f7bb665'; 22 | -------------------------------------------------------------------------------- /test/nestableSecTests.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { ethers } from 'hardhat'; 3 | import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; 4 | import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; 5 | import { RMRKNestableMock, ChildAdder } from '../typechain-types'; 6 | 7 | async function nestableFixture() { 8 | const NestableFactory = await ethers.getContractFactory('RMRKNestableMock'); 9 | const parent = await NestableFactory.deploy(); 10 | await parent.waitForDeployment(); 11 | 12 | return parent; 13 | } 14 | 15 | describe('Nestable with ChildAdder', function () { 16 | let parent: RMRKNestableMock; 17 | let adder: ChildAdder; 18 | let owner: SignerWithAddress; 19 | 20 | beforeEach(async function () { 21 | owner = (await ethers.getSigners())[0]; 22 | parent = await loadFixture(nestableFixture); 23 | const Childadder = await ethers.getContractFactory('ChildAdder'); 24 | adder = await Childadder.deploy(); 25 | await adder.waitForDeployment(); 26 | }); 27 | 28 | describe('add children', async function () { 29 | it('cannot add multiple children', async function () { 30 | await parent.connect(owner).mint(owner.address, 1); 31 | // Propose 10 children with the same params to the parent token 32 | await adder.addChild(await parent.getAddress(), 1, 1, 10); 33 | 34 | await parent.connect(owner).acceptChild(1, 0, await adder.getAddress(), 1); 35 | await expect( 36 | parent.connect(owner).acceptChild(1, 0, await adder.getAddress(), 1), 37 | ).to.be.revertedWithCustomError(parent, 'RMRKChildAlreadyExists'); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/ownableLock.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat'; 2 | 3 | import shouldBehaveLikeOwnableLock from './behavior/ownableLock'; 4 | import { OwnableLockMock } from '../typechain-types'; 5 | 6 | describe('Ownable Lock', async () => { 7 | let token: OwnableLockMock; 8 | 9 | const ismock = true; 10 | 11 | beforeEach(async function () { 12 | const OLOCK = await ethers.getContractFactory('OwnableLockMock'); 13 | token = await OLOCK.deploy(); 14 | await token.waitForDeployment(); 15 | this.token = token; 16 | }); 17 | 18 | shouldBehaveLikeOwnableLock(ismock); 19 | }); 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "lib": ["ES2020", "esnext", "dom"], 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "outDir": "dist", 10 | "declaration": true, 11 | "resolveJsonModule": true, 12 | }, 13 | "include": ["./scripts", "./test", "./typechain-types"], 14 | "exclude": ["node_modules", "dist"], 15 | "files": ["./hardhat.config.ts"], 16 | } 17 | --------------------------------------------------------------------------------