|
| 1 | +# Contract ERC-721 Plugin |
| 2 | + |
| 3 | +ERC-721 (NFT) token interface plugin for the Hiero CLI. Provides commands to call standard ERC-721 (EIP-721) smart contract functions on Hedera. Contracts must be deployed first using the [contract plugin](../contract/README.md). |
| 4 | + |
| 5 | +## 🏗️ Architecture |
| 6 | + |
| 7 | +This plugin follows the plugin architecture principles: |
| 8 | + |
| 9 | +- **Stateless**: Plugin is functionally stateless |
| 10 | +- **Dependency Injection**: Services are injected into command handlers |
| 11 | +- **Manifest-Driven**: Capabilities declared via manifest |
| 12 | +- **Type Safety**: Full TypeScript support |
| 13 | + |
| 14 | +## 📁 Structure |
| 15 | + |
| 16 | +``` |
| 17 | +src/plugins/contract-erc721/ |
| 18 | +├── manifest.ts # Plugin manifest with command definitions |
| 19 | +├── shared/ |
| 20 | +│ └── erc721-abi.ts # ERC-721 ABI interface definition |
| 21 | +├── commands/ |
| 22 | +│ ├── name/ # name() view function |
| 23 | +│ ├── symbol/ # symbol() view function |
| 24 | +│ ├── balance-of/ # balanceOf(address) view function |
| 25 | +│ ├── owner-of/ # ownerOf(tokenId) view function |
| 26 | +│ ├── get-approved/ # getApproved(tokenId) view function |
| 27 | +│ ├── is-approved-for-all/ # isApprovedForAll(owner, operator) view function |
| 28 | +│ ├── token-uri/ # tokenURI(tokenId) view function |
| 29 | +│ ├── approve/ # approve(to, tokenId) state-changing |
| 30 | +│ ├── set-approval-for-all/ # setApprovalForAll(operator, approved) state-changing |
| 31 | +│ ├── transfer-from/ # transferFrom(from, to, tokenId) state-changing |
| 32 | +│ ├── safe-transfer-from/ # safeTransferFrom(from, to, tokenId [, data]) state-changing |
| 33 | +│ └── mint/ # mint(to, tokenId) state-changing (experimental) |
| 34 | +├── __tests__/unit/ # Unit tests |
| 35 | +└── index.ts # Plugin exports |
| 36 | +``` |
| 37 | + |
| 38 | +Each command folder contains: `handler.ts`, `input.ts`, `output.ts`, `index.ts`, and optionally `result.ts` for view functions. |
| 39 | + |
| 40 | +## 🚀 Commands |
| 41 | + |
| 42 | +All commands return `CommandExecutionResult` with structured output. Contract and account references accept **alias**, **Hedera entity ID** (0.0.xxx), or **EVM address** (0x...). |
| 43 | + |
| 44 | +### View Functions (read-only, no transaction) |
| 45 | + |
| 46 | +| Command | Description | |
| 47 | +| --------------------- | --------------------------------------------------- | |
| 48 | +| `name` | Token collection name | |
| 49 | +| `symbol` | Token symbol | |
| 50 | +| `balance-of` | NFT balance of an owner | |
| 51 | +| `owner-of` | Owner of a token by ID | |
| 52 | +| `get-approved` | Approved address for a token | |
| 53 | +| `is-approved-for-all` | Whether operator is approved for all owner's tokens | |
| 54 | +| `token-uri` | Metadata URI for a token | |
| 55 | + |
| 56 | +### State-Changing Functions (require transaction, signed by operator) |
| 57 | + |
| 58 | +| Command | Description | |
| 59 | +| ---------------------- | ------------------------------------------------------- | |
| 60 | +| `approve` | Approve address to transfer a specific token | |
| 61 | +| `set-approval-for-all` | Approve or revoke operator for all tokens | |
| 62 | +| `transfer-from` | Transfer token from one address to another | |
| 63 | +| `safe-transfer-from` | Safe transfer with optional data payload | |
| 64 | +| `mint` | Mint new token (experimental, requires custom contract) | |
| 65 | + |
| 66 | +### name |
| 67 | + |
| 68 | +```bash |
| 69 | +hcli contract-erc721 name --contract my-nft |
| 70 | +``` |
| 71 | + |
| 72 | +| Option | Short | Required | Description | |
| 73 | +| ---------- | ----- | -------- | -------------------- | |
| 74 | +| `contract` | `c` | Yes | Contract alias or ID | |
| 75 | + |
| 76 | +### symbol |
| 77 | + |
| 78 | +```bash |
| 79 | +hcli contract-erc721 symbol --contract my-nft |
| 80 | +``` |
| 81 | + |
| 82 | +| Option | Short | Required | Description | |
| 83 | +| ---------- | ----- | -------- | -------------------- | |
| 84 | +| `contract` | `c` | Yes | Contract alias or ID | |
| 85 | + |
| 86 | +### balance-of |
| 87 | + |
| 88 | +```bash |
| 89 | +hcli contract-erc721 balance-of --contract my-nft --owner alice |
| 90 | +``` |
| 91 | + |
| 92 | +| Option | Short | Required | Description | |
| 93 | +| ---------- | ----- | -------- | -------------------------------------- | |
| 94 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | |
| 95 | +| `owner` | `o` | Yes | Owner account alias, ID or EVM address | |
| 96 | + |
| 97 | +### owner-of |
| 98 | + |
| 99 | +```bash |
| 100 | +hcli contract-erc721 owner-of --contract my-nft --token-id 1 |
| 101 | +``` |
| 102 | + |
| 103 | +| Option | Short | Required | Description | |
| 104 | +| ---------- | ----- | -------- | -------------------- | |
| 105 | +| `contract` | `c` | Yes | Contract alias or ID | |
| 106 | +| `token-id` | `T` | Yes | Token ID (uint256) | |
| 107 | + |
| 108 | +### get-approved |
| 109 | + |
| 110 | +```bash |
| 111 | +hcli contract-erc721 get-approved --contract my-nft --token-id 1 |
| 112 | +``` |
| 113 | + |
| 114 | +| Option | Short | Required | Description | |
| 115 | +| ---------- | ----- | -------- | -------------------- | |
| 116 | +| `contract` | `c` | Yes | Contract alias or ID | |
| 117 | +| `token-id` | `T` | Yes | Token ID to query | |
| 118 | + |
| 119 | +### is-approved-for-all |
| 120 | + |
| 121 | +```bash |
| 122 | +hcli contract-erc721 is-approved-for-all --contract my-nft --owner alice --operator bob |
| 123 | +``` |
| 124 | + |
| 125 | +| Option | Short | Required | Description | |
| 126 | +| ---------- | ----- | -------- | ----------------------------------------- | |
| 127 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | |
| 128 | +| `owner` | `o` | Yes | Owner account alias, ID or EVM address | |
| 129 | +| `operator` | `p` | Yes | Operator account alias, ID or EVM address | |
| 130 | + |
| 131 | +### token-uri |
| 132 | + |
| 133 | +```bash |
| 134 | +hcli contract-erc721 token-uri --contract my-nft --token-id 1 |
| 135 | +``` |
| 136 | + |
| 137 | +| Option | Short | Required | Description | |
| 138 | +| ---------- | ----- | -------- | -------------------- | |
| 139 | +| `contract` | `c` | Yes | Contract alias or ID | |
| 140 | +| `token-id` | `T` | Yes | Token ID to query | |
| 141 | + |
| 142 | +### approve |
| 143 | + |
| 144 | +Approves an address to transfer a specific token. Operator must be the token owner. |
| 145 | + |
| 146 | +```bash |
| 147 | +hcli contract-erc721 approve --contract my-nft --to bob --token-id 1 |
| 148 | +``` |
| 149 | + |
| 150 | +| Option | Short | Required | Description | Default | |
| 151 | +| ---------- | ----- | -------- | --------------------------------------------- | ------- | |
| 152 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | - | |
| 153 | +| `to` | `t` | Yes | Address to approve (alias, ID or EVM address) | - | |
| 154 | +| `token-id` | `T` | Yes | Token ID to approve | - | |
| 155 | +| `gas` | `g` | No | Gas for function call | 100000 | |
| 156 | + |
| 157 | +### set-approval-for-all |
| 158 | + |
| 159 | +Approves or revokes an operator for all tokens owned by the caller. |
| 160 | + |
| 161 | +```bash |
| 162 | +hcli contract-erc721 set-approval-for-all --contract my-nft --operator bob --approved true |
| 163 | +``` |
| 164 | + |
| 165 | +| Option | Short | Required | Description | Default | |
| 166 | +| ---------- | ----- | -------- | ----------------------------------------- | ------- | |
| 167 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | - | |
| 168 | +| `operator` | `o` | Yes | Operator account alias, ID or EVM address | - | |
| 169 | +| `approved` | `a` | Yes | "true" or "false" | - | |
| 170 | +| `gas` | `g` | No | Gas for function call | 100000 | |
| 171 | + |
| 172 | +### transfer-from |
| 173 | + |
| 174 | +Transfers a token from one address to another. Caller must be owner, approved, or approved for all. |
| 175 | + |
| 176 | +```bash |
| 177 | +hcli contract-erc721 transfer-from --contract my-nft --from alice --to bob --token-id 1 |
| 178 | +``` |
| 179 | + |
| 180 | +| Option | Short | Required | Description | Default | |
| 181 | +| ---------- | ----- | -------- | ---------------------------------------- | ------- | |
| 182 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | - | |
| 183 | +| `from` | `f` | Yes | Current owner (alias, ID or EVM address) | - | |
| 184 | +| `to` | `t` | Yes | Recipient (alias, ID or EVM address) | - | |
| 185 | +| `token-id` | `T` | Yes | Token ID to transfer | - | |
| 186 | +| `gas` | `g` | No | Gas for function call | 100000 | |
| 187 | + |
| 188 | +### safe-transfer-from |
| 189 | + |
| 190 | +Safe transfer with optional data. Reverts if recipient is a contract that does not implement the receiver interface. |
| 191 | + |
| 192 | +```bash |
| 193 | +hcli contract-erc721 safe-transfer-from --contract my-nft --from alice --to bob --token-id 1 |
| 194 | +hcli contract-erc721 safe-transfer-from -c my-nft -f alice -t bob -T 1 -d 0x1234 |
| 195 | +``` |
| 196 | + |
| 197 | +| Option | Short | Required | Description | Default | |
| 198 | +| ---------- | ----- | -------- | -------------------------------------------- | ------- | |
| 199 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | - | |
| 200 | +| `from` | `f` | Yes | Current owner (alias, ID or EVM address) | - | |
| 201 | +| `to` | `t` | Yes | Recipient (alias, ID or EVM address) | - | |
| 202 | +| `token-id` | `T` | Yes | Token ID to transfer | - | |
| 203 | +| `data` | `d` | No | Optional hex-encoded data for 4-arg overload | - | |
| 204 | +| `gas` | `g` | No | Gas for function call | 100000 | |
| 205 | + |
| 206 | +### mint |
| 207 | + |
| 208 | +**⚠️ EXPERIMENTAL** – Calls custom `mint(address to, uint256 tokenId)`. Requires contract to implement this function (e.g. via OpenZeppelin `_mint`). |
| 209 | + |
| 210 | +```bash |
| 211 | +hcli contract-erc721 mint --contract my-nft --to alice --token-id 1 |
| 212 | +``` |
| 213 | + |
| 214 | +| Option | Short | Required | Description | Default | |
| 215 | +| ---------- | ----- | -------- | -------------------------------------------- | ------- | |
| 216 | +| `contract` | `c` | Yes | Contract alias, ID or EVM address | - | |
| 217 | +| `to` | `t` | Yes | Recipient address (alias, ID or EVM address) | - | |
| 218 | +| `token-id` | `T` | Yes | Token ID to mint | - | |
| 219 | +| `gas` | `g` | No | Gas for function call | 100000 | |
| 220 | + |
| 221 | +## 🔧 Core API Integration |
| 222 | + |
| 223 | +The plugin uses the Core API services: |
| 224 | + |
| 225 | +- `api.contract` - Contract execute transaction creation |
| 226 | +- `api.contractQuery` - Read-only contract calls (view functions) |
| 227 | +- `api.txExecution` - Transaction signing and execution |
| 228 | +- `api.identityResolution` - Resolve alias, entity ID, or EVM address to contract/account info |
| 229 | +- `api.network` - Current network |
| 230 | +- `api.logger` - Logging |
| 231 | + |
| 232 | +## 📤 Output Formatting |
| 233 | + |
| 234 | +All commands return structured output through the `CommandExecutionResult` interface. View functions return query results; state-changing functions return `contractId`, `network`, and `transactionId`. |
| 235 | + |
| 236 | +Human-readable output uses Handlebars templates with HashScan links for contract and transaction IDs. |
| 237 | + |
| 238 | +## 🏷️ Identity Resolution |
| 239 | + |
| 240 | +Contract and account parameters support flexible referencing: |
| 241 | + |
| 242 | +- **Alias**: Registered name (e.g. `my-nft`, `alice`) – resolved via alias service |
| 243 | +- **Entity ID**: Hedera format (e.g. `0.0.123456`) |
| 244 | +- **EVM address**: Hex format (e.g. `0x1234...`) |
| 245 | + |
| 246 | +View functions resolve contracts synchronously. State-changing functions resolve contracts via Mirror Node for full contract info. |
| 247 | + |
| 248 | +## 🧪 Testing |
| 249 | + |
| 250 | +Unit tests located in `__tests__/unit/`: |
| 251 | + |
| 252 | +```bash |
| 253 | +npm run test:unit -- src/plugins/contract-erc721/__tests__/unit |
| 254 | +``` |
0 commit comments