├── .gitignore ├── README.md ├── generated ├── build │ ├── erc721 │ │ └── erc721.wasm │ ├── node_modules │ │ └── @openzeppelin │ │ │ └── contracts │ │ │ └── build │ │ │ └── contracts │ │ │ ├── IERC721Metadata.json │ │ │ └── Ownable.json │ ├── ownable │ │ └── ownable.wasm │ ├── sample.schema.graphql │ └── subgraph.yaml ├── sample.schema.graphql └── subgraph.yaml ├── package.json ├── sluganddeploykey.png ├── subgraphconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Building NFT APIs with OpenZeppelin and The Graph 2 | 3 | OpenZeppelin recently released [OpenZeppelin Subgraphs](https://docs.openzeppelin.com/subgraphs/0.1.x/), a set of modules and CLI tools that make it easy to index OpenZeppelin contracts activity and make it available via an open API using The Graph Protocol. 4 | 5 | These tools abstract away a lot of the code that you'd typically need to write to create a Subgraph when using various modules that OpenZeppelin supports. 6 | 7 | As of now, the project supports these modules: 8 | 9 | - AccessControl 10 | - ERC20 11 | - ERC721 12 | - ERC1155 13 | - ERC1967Upgrade 14 | - Governor 15 | - Ownable 16 | - Pausable 17 | - Timelock 18 | 19 | Using the project, you can get up and running with a subgraph in just a few minutes, either deploying it as is, or using it as a boilerplate and adding your own customizations. 20 | 21 | ### What we'll be building 22 | 23 | In this guide, we'll look at how to leverage OpenZeppelin Subgraphs to build an NFT API that indexes and makes data queryable from a few NFT smart contracts - Cool Cats and Pudgy Penguins. 24 | 25 | The API will allow us to query NFT data from these two projects, making both the NFT data as well as the data from the acounts that own the NFTs available. 26 | 27 | Here are the smart contract addresses that we'll be working with: 28 | 29 | - [Cool Cats](https://etherscan.io/address/0x1a92f7381b9f03921564a437210bb9396471050c) 30 | - [Pudgy Penguins](https://etherscan.io/address/0xBd3531dA5CF5857e7CfAA92426877b022e612cf8) 31 | 32 | ### Dependencies 33 | 34 | To be successful in this guide, you will need the following 35 | 36 | - Node.js - Consider [nvm](https://github.com/nvm-sh/nvm) to install Node.js on your machine 37 | - [Graph CLI](https://github.com/graphprotocol/graph-cli) 38 | - Metamask or WalletConnect compatible wallet 39 | 40 | ### Getting started 41 | 42 | To get started, we'll first need to initialize a new subgraph in the Subgraph Studio. 43 | 44 | Go to [https://thegraph.com/studio/](https://thegraph.com/studio/) and click __Connect Wallet__ to connect your Ethereum wallet. 45 | 46 | Next, click __Create a Subgraph__ to create a new subgraph. 47 | 48 | Here, give the subgraph a name (like FunNFTs) and click __Continue__. 49 | 50 | Now the subgraph has been initialized in the Subgraph Studio and we can continue to our local development environment. 51 | 52 | ### Building the subgraph 53 | 54 | Next, we'll create a new folder and initialize a new `package.json` file: 55 | 56 | ```sh 57 | npm init --y 58 | ``` 59 | 60 | Next, install the OpenZeppelin Subgraph package: 61 | 62 | ```sh 63 | npm install @openzeppelin/subgraphs 64 | ``` 65 | 66 | Now all we need to do is define the smart contract addresses as well as the entity types that we'd like to index. 67 | 68 | To do so, we can create a new file named __subgraphconfig.json__ and add the following lines of configuration: 69 | 70 | ```json 71 | { 72 | "output": "generated/", 73 | "chain": "mainnet", 74 | "datasources": [ 75 | { "address": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", "startBlock": 12878203, "module": [ "erc721", "ownable" ] }, 76 | { "address": "0x1a92f7381b9f03921564a437210bb9396471050c", "startBlock": 12743024, "module": [ "erc721", "ownable" ] } 77 | ] 78 | } 79 | ``` 80 | 81 | The array of data sources allows us to define the following properties for each item in the array: 82 | 83 | - Smart contract address 84 | - The start block (optional) 85 | - Array of entities / modules that we'd like to index. 86 | 87 | In the coonfiguration we've created, we've decided to index both the `erc721` token data as well as `ownable` for indexing the ownership information of the tokens. 88 | 89 | That is all of the configuration we need! We can now build the subgraph. 90 | 91 | To build the subgraph, run the following command: 92 | 93 | ```sh 94 | npx graph-compiler \ 95 | --config subgraphconfig.json \ 96 | --include node_modules/@openzeppelin/subgraphs/src/datasources \ 97 | --export-schema \ 98 | --export-subgraph 99 | ``` 100 | 101 | After running this command, you should have the subgraph compiled in a new folder named __generated__. In this folder, you should see two files: 102 | 103 | - __schema.graphql__ - The GraphQL schema / data model 104 | - __subgraph.yaml__ - The main subgraph configuration 105 | 106 | Now we are ready to deploy. 107 | 108 | ### Deploying and testing the subgraph 109 | 110 | To deploy to Subgraph Studio and begin testing out the API, we need to have the subgraoh __DEPLOY KEY__ as well as the __SUBGRAPH SLUG__, both of which are available in the Subgraph Studio dashboard for the individual subgraph. 111 | 112 | ![Slug and deploy key](sluganddeploykey.png) 113 | 114 | First, change into the newly created __generated__ folder: 115 | 116 | ```sh 117 | cd generated 118 | ``` 119 | 120 | Next, we'll use the Graph CLI to authenticate and authorize the deployment from your local environment: 121 | 122 | ```sh 123 | graph auth --studio 124 | 125 | > Paste in DEPLOY KEY when prompted 126 | ``` 127 | 128 | Now, we can deploy by running the following command: 129 | 130 | ```sh 131 | graph deploy --studio 132 | ``` 133 | 134 | Once the deployment is complete, you should be ready to start testing it out! 135 | 136 | ### Testing out the API 137 | 138 | In the Subgraph Studio you can run queries using the built in GraphQL Playground. 139 | 140 | The first query we'll run will be to just return the NFT token data: 141 | 142 | ```graphql 143 | { 144 | erc721Tokens { 145 | id 146 | identifier 147 | uri 148 | } 149 | } 150 | ``` 151 | 152 | We can also enhance this query by passing in arguments, for instance if we wanted to order by the token `identifier`: 153 | 154 | ```graphql 155 | { 156 | erc721Tokens( 157 | orderBy: identifier, 158 | orderDirection: asc 159 | ) { 160 | id 161 | identifier 162 | uri 163 | } 164 | } 165 | ``` 166 | 167 | We can query for transfer events, in the order in which they were transferred: 168 | 169 | ```graphql 170 | { 171 | erc721Transfers( 172 | orderBy: timestamp 173 | orderDirection: desc 174 | ) { 175 | timestamp 176 | token { 177 | identifier 178 | uri 179 | } 180 | } 181 | } 182 | ``` 183 | 184 | Finally, we may want to query for users and their tokens: 185 | 186 | ```graphql 187 | { 188 | accounts { 189 | id 190 | ERC721tokens { 191 | identifier 192 | uri 193 | } 194 | } 195 | } 196 | ``` 197 | 198 | ### Next steps 199 | 200 | The API is now ready to deploy. You can test it out in your front end application by following [this guide](https://thegraph.com/docs/developer/querying-from-your-app), using the __TEMPORARY QUERY URL__ given to you by the Subgraph Studio in the __Details__ view. 201 | 202 | When you are ready to put your API into production, you can [publish your subgraph to the decentrlized network](https://thegraph.com/docs/studio/subgraph-studio#publish-your-subgraphs). 203 | 204 | To learn how to build a subgraph from scratch, have a look at [this guide](https://thegraph.com/blog/building-with-subgraph-studio). -------------------------------------------------------------------------------- /generated/build/erc721/erc721.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/openzeppelin-nft-api/1b44ca2901949b26037b405009bf892b8027307a/generated/build/erc721/erc721.wasm -------------------------------------------------------------------------------- /generated/build/node_modules/@openzeppelin/contracts/build/contracts/IERC721Metadata.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "owner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "approved", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": true, 19 | "internalType": "uint256", 20 | "name": "tokenId", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "Approval", 25 | "type": "event" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "address", 33 | "name": "owner", 34 | "type": "address" 35 | }, 36 | { 37 | "indexed": true, 38 | "internalType": "address", 39 | "name": "operator", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "bool", 45 | "name": "approved", 46 | "type": "bool" 47 | } 48 | ], 49 | "name": "ApprovalForAll", 50 | "type": "event" 51 | }, 52 | { 53 | "anonymous": false, 54 | "inputs": [ 55 | { 56 | "indexed": true, 57 | "internalType": "address", 58 | "name": "from", 59 | "type": "address" 60 | }, 61 | { 62 | "indexed": true, 63 | "internalType": "address", 64 | "name": "to", 65 | "type": "address" 66 | }, 67 | { 68 | "indexed": true, 69 | "internalType": "uint256", 70 | "name": "tokenId", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "Transfer", 75 | "type": "event" 76 | }, 77 | { 78 | "inputs": [ 79 | { 80 | "internalType": "address", 81 | "name": "to", 82 | "type": "address" 83 | }, 84 | { 85 | "internalType": "uint256", 86 | "name": "tokenId", 87 | "type": "uint256" 88 | } 89 | ], 90 | "name": "approve", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "owner", 100 | "type": "address" 101 | } 102 | ], 103 | "name": "balanceOf", 104 | "outputs": [ 105 | { 106 | "internalType": "uint256", 107 | "name": "balance", 108 | "type": "uint256" 109 | } 110 | ], 111 | "stateMutability": "view", 112 | "type": "function" 113 | }, 114 | { 115 | "inputs": [ 116 | { 117 | "internalType": "uint256", 118 | "name": "tokenId", 119 | "type": "uint256" 120 | } 121 | ], 122 | "name": "getApproved", 123 | "outputs": [ 124 | { 125 | "internalType": "address", 126 | "name": "operator", 127 | "type": "address" 128 | } 129 | ], 130 | "stateMutability": "view", 131 | "type": "function" 132 | }, 133 | { 134 | "inputs": [ 135 | { 136 | "internalType": "address", 137 | "name": "owner", 138 | "type": "address" 139 | }, 140 | { 141 | "internalType": "address", 142 | "name": "operator", 143 | "type": "address" 144 | } 145 | ], 146 | "name": "isApprovedForAll", 147 | "outputs": [ 148 | { 149 | "internalType": "bool", 150 | "name": "", 151 | "type": "bool" 152 | } 153 | ], 154 | "stateMutability": "view", 155 | "type": "function" 156 | }, 157 | { 158 | "inputs": [], 159 | "name": "name", 160 | "outputs": [ 161 | { 162 | "internalType": "string", 163 | "name": "", 164 | "type": "string" 165 | } 166 | ], 167 | "stateMutability": "view", 168 | "type": "function" 169 | }, 170 | { 171 | "inputs": [ 172 | { 173 | "internalType": "uint256", 174 | "name": "tokenId", 175 | "type": "uint256" 176 | } 177 | ], 178 | "name": "ownerOf", 179 | "outputs": [ 180 | { 181 | "internalType": "address", 182 | "name": "owner", 183 | "type": "address" 184 | } 185 | ], 186 | "stateMutability": "view", 187 | "type": "function" 188 | }, 189 | { 190 | "inputs": [ 191 | { 192 | "internalType": "address", 193 | "name": "from", 194 | "type": "address" 195 | }, 196 | { 197 | "internalType": "address", 198 | "name": "to", 199 | "type": "address" 200 | }, 201 | { 202 | "internalType": "uint256", 203 | "name": "tokenId", 204 | "type": "uint256" 205 | } 206 | ], 207 | "name": "safeTransferFrom", 208 | "outputs": [], 209 | "stateMutability": "nonpayable", 210 | "type": "function" 211 | }, 212 | { 213 | "inputs": [ 214 | { 215 | "internalType": "address", 216 | "name": "from", 217 | "type": "address" 218 | }, 219 | { 220 | "internalType": "address", 221 | "name": "to", 222 | "type": "address" 223 | }, 224 | { 225 | "internalType": "uint256", 226 | "name": "tokenId", 227 | "type": "uint256" 228 | }, 229 | { 230 | "internalType": "bytes", 231 | "name": "data", 232 | "type": "bytes" 233 | } 234 | ], 235 | "name": "safeTransferFrom", 236 | "outputs": [], 237 | "stateMutability": "nonpayable", 238 | "type": "function" 239 | }, 240 | { 241 | "inputs": [ 242 | { 243 | "internalType": "address", 244 | "name": "operator", 245 | "type": "address" 246 | }, 247 | { 248 | "internalType": "bool", 249 | "name": "_approved", 250 | "type": "bool" 251 | } 252 | ], 253 | "name": "setApprovalForAll", 254 | "outputs": [], 255 | "stateMutability": "nonpayable", 256 | "type": "function" 257 | }, 258 | { 259 | "inputs": [ 260 | { 261 | "internalType": "bytes4", 262 | "name": "interfaceId", 263 | "type": "bytes4" 264 | } 265 | ], 266 | "name": "supportsInterface", 267 | "outputs": [ 268 | { 269 | "internalType": "bool", 270 | "name": "", 271 | "type": "bool" 272 | } 273 | ], 274 | "stateMutability": "view", 275 | "type": "function" 276 | }, 277 | { 278 | "inputs": [], 279 | "name": "symbol", 280 | "outputs": [ 281 | { 282 | "internalType": "string", 283 | "name": "", 284 | "type": "string" 285 | } 286 | ], 287 | "stateMutability": "view", 288 | "type": "function" 289 | }, 290 | { 291 | "inputs": [ 292 | { 293 | "internalType": "uint256", 294 | "name": "tokenId", 295 | "type": "uint256" 296 | } 297 | ], 298 | "name": "tokenURI", 299 | "outputs": [ 300 | { 301 | "internalType": "string", 302 | "name": "", 303 | "type": "string" 304 | } 305 | ], 306 | "stateMutability": "view", 307 | "type": "function" 308 | }, 309 | { 310 | "inputs": [ 311 | { 312 | "internalType": "address", 313 | "name": "from", 314 | "type": "address" 315 | }, 316 | { 317 | "internalType": "address", 318 | "name": "to", 319 | "type": "address" 320 | }, 321 | { 322 | "internalType": "uint256", 323 | "name": "tokenId", 324 | "type": "uint256" 325 | } 326 | ], 327 | "name": "transferFrom", 328 | "outputs": [], 329 | "stateMutability": "nonpayable", 330 | "type": "function" 331 | } 332 | ] -------------------------------------------------------------------------------- /generated/build/node_modules/@openzeppelin/contracts/build/contracts/Ownable.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "owner", 24 | "outputs": [ 25 | { 26 | "internalType": "address", 27 | "name": "", 28 | "type": "address" 29 | } 30 | ], 31 | "stateMutability": "view", 32 | "type": "function" 33 | }, 34 | { 35 | "inputs": [], 36 | "name": "renounceOwnership", 37 | "outputs": [], 38 | "stateMutability": "nonpayable", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "newOwner", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "transferOwnership", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | } 54 | ] -------------------------------------------------------------------------------- /generated/build/ownable/ownable.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/openzeppelin-nft-api/1b44ca2901949b26037b405009bf892b8027307a/generated/build/ownable/ownable.wasm -------------------------------------------------------------------------------- /generated/build/sample.schema.graphql: -------------------------------------------------------------------------------- 1 | type Account @entity { 2 | id: ID! 3 | asERC721: ERC721Contract 4 | ERC721tokens: [ERC721Token]! @derivedFrom(field: "owner") 5 | ERC721operatorOwner: [ERC721Operator]! @derivedFrom(field: "owner") 6 | ERC721operatorOperator: [ERC721Operator]! @derivedFrom(field: "operator") 7 | ERC721transferFromEvent: [ERC721Transfer]! @derivedFrom(field: "from") 8 | ERC721transferToEvent: [ERC721Transfer]! @derivedFrom(field: "to") 9 | asOwnable: Ownable 10 | ownerOf: [Ownable!]! @derivedFrom(field: "owner") 11 | ownershipTransferred: [OwnershipTransferred!]! @derivedFrom(field: "owner") 12 | } 13 | type ERC721Contract @entity { 14 | id: ID! 15 | asAccount: Account! 16 | supportsMetadata: Boolean 17 | name: String 18 | symbol: String 19 | tokens: [ERC721Token!]! @derivedFrom(field: "contract") 20 | operators: [ERC721Operator!]! @derivedFrom(field: "contract") 21 | transfers: [ERC721Transfer!]! @derivedFrom(field: "contract") 22 | } 23 | type ERC721Token @entity { 24 | id: ID! 25 | contract: ERC721Contract! 26 | identifier: BigInt! 27 | owner: Account! 28 | approval: Account! 29 | uri: String 30 | transfers: [ERC721Transfer!]! @derivedFrom(field: "token") 31 | } 32 | type ERC721Operator @entity { 33 | id: ID! 34 | contract: ERC721Contract! 35 | owner: Account! 36 | operator: Account! 37 | approved: Boolean! 38 | } 39 | type ERC721Transfer implements Event @entity { 40 | id: ID! 41 | transaction: Transaction! 42 | timestamp: BigInt! 43 | contract: ERC721Contract! 44 | token: ERC721Token! 45 | from: Account! 46 | to: Account! 47 | } 48 | type Ownable @entity { 49 | id: ID! 50 | asAccount: Account! 51 | owner: Account! 52 | ownershipTransferred: [OwnershipTransferred!]! @derivedFrom(field: "contract") 53 | } 54 | type OwnershipTransferred implements Event @entity { 55 | id: ID! 56 | transaction: Transaction! 57 | timestamp: BigInt! 58 | contract: Ownable! 59 | owner: Account! 60 | } 61 | interface Event { 62 | id: ID! 63 | transaction: Transaction! 64 | timestamp: BigInt! 65 | } 66 | type Transaction @entity { 67 | id: ID! 68 | timestamp: BigInt! 69 | blockNumber: BigInt! 70 | events: [Event!]! @derivedFrom(field: "transaction") 71 | } 72 | -------------------------------------------------------------------------------- /generated/build/subgraph.yaml: -------------------------------------------------------------------------------- 1 | specVersion: 0.0.2 2 | schema: 3 | file: sample.schema.graphql 4 | dataSources: 5 | - kind: ethereum/contract 6 | name: erc721 7 | network: mainnet 8 | source: 9 | address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8" 10 | abi: IERC721 11 | startBlock: 12878203 12 | mapping: 13 | kind: ethereum/events 14 | apiVersion: 0.0.4 15 | language: wasm/assemblyscript 16 | entities: 17 | - ERC721Contract 18 | abis: 19 | - name: IERC721 20 | file: node_modules/@openzeppelin/contracts/build/contracts/IERC721Metadata.json 21 | eventHandlers: 22 | - event: Approval(indexed address,indexed address,indexed uint256) 23 | handler: handleApproval 24 | - event: ApprovalForAll(indexed address,indexed address,bool) 25 | handler: handleApprovalForAll 26 | - event: Transfer(indexed address,indexed address,indexed uint256) 27 | handler: handleTransfer 28 | file: erc721/erc721.wasm 29 | - kind: ethereum/contract 30 | name: ownable 31 | network: mainnet 32 | source: 33 | address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8" 34 | abi: Ownable 35 | startBlock: 12878203 36 | mapping: 37 | kind: ethereum/events 38 | apiVersion: 0.0.4 39 | language: wasm/assemblyscript 40 | entities: 41 | - Ownable 42 | abis: 43 | - name: Ownable 44 | file: node_modules/@openzeppelin/contracts/build/contracts/Ownable.json 45 | eventHandlers: 46 | - event: OwnershipTransferred(indexed address,indexed address) 47 | handler: handleOwnershipTransferred 48 | file: ownable/ownable.wasm 49 | - kind: ethereum/contract 50 | name: erc721-2 51 | network: mainnet 52 | source: 53 | address: "0x1a92f7381b9f03921564a437210bb9396471050c" 54 | abi: IERC721 55 | startBlock: 12743024 56 | mapping: 57 | kind: ethereum/events 58 | apiVersion: 0.0.4 59 | language: wasm/assemblyscript 60 | entities: 61 | - ERC721Contract 62 | abis: 63 | - name: IERC721 64 | file: node_modules/@openzeppelin/contracts/build/contracts/IERC721Metadata.json 65 | eventHandlers: 66 | - event: Approval(indexed address,indexed address,indexed uint256) 67 | handler: handleApproval 68 | - event: ApprovalForAll(indexed address,indexed address,bool) 69 | handler: handleApprovalForAll 70 | - event: Transfer(indexed address,indexed address,indexed uint256) 71 | handler: handleTransfer 72 | file: erc721/erc721.wasm 73 | - kind: ethereum/contract 74 | name: ownable-3 75 | network: mainnet 76 | source: 77 | address: "0x1a92f7381b9f03921564a437210bb9396471050c" 78 | abi: Ownable 79 | startBlock: 12743024 80 | mapping: 81 | kind: ethereum/events 82 | apiVersion: 0.0.4 83 | language: wasm/assemblyscript 84 | entities: 85 | - Ownable 86 | abis: 87 | - name: Ownable 88 | file: node_modules/@openzeppelin/contracts/build/contracts/Ownable.json 89 | eventHandlers: 90 | - event: OwnershipTransferred(indexed address,indexed address) 91 | handler: handleOwnershipTransferred 92 | file: ownable/ownable.wasm 93 | -------------------------------------------------------------------------------- /generated/sample.schema.graphql: -------------------------------------------------------------------------------- 1 | type Account @entity { 2 | id: ID! 3 | asERC721: ERC721Contract 4 | ERC721tokens: [ERC721Token]! @derivedFrom(field: "owner") 5 | ERC721operatorOwner: [ERC721Operator]! @derivedFrom(field: "owner") 6 | ERC721operatorOperator: [ERC721Operator]! @derivedFrom(field: "operator") 7 | ERC721transferFromEvent: [ERC721Transfer]! @derivedFrom(field: "from") 8 | ERC721transferToEvent: [ERC721Transfer]! @derivedFrom(field: "to") 9 | asOwnable: Ownable 10 | ownerOf: [Ownable!]! @derivedFrom(field: "owner") 11 | ownershipTransferred: [OwnershipTransferred!]! @derivedFrom(field: "owner") 12 | } 13 | type ERC721Contract @entity { 14 | id: ID! 15 | asAccount: Account! 16 | supportsMetadata: Boolean 17 | name: String 18 | symbol: String 19 | tokens: [ERC721Token!]! @derivedFrom(field: "contract") 20 | operators: [ERC721Operator!]! @derivedFrom(field: "contract") 21 | transfers: [ERC721Transfer!]! @derivedFrom(field: "contract") 22 | } 23 | type ERC721Token @entity { 24 | id: ID! 25 | contract: ERC721Contract! 26 | identifier: BigInt! 27 | owner: Account! 28 | approval: Account! 29 | uri: String 30 | transfers: [ERC721Transfer!]! @derivedFrom(field: "token") 31 | } 32 | type ERC721Operator @entity { 33 | id: ID! 34 | contract: ERC721Contract! 35 | owner: Account! 36 | operator: Account! 37 | approved: Boolean! 38 | } 39 | type ERC721Transfer implements Event @entity { 40 | id: ID! 41 | transaction: Transaction! 42 | timestamp: BigInt! 43 | contract: ERC721Contract! 44 | token: ERC721Token! 45 | from: Account! 46 | to: Account! 47 | } 48 | type Ownable @entity { 49 | id: ID! 50 | asAccount: Account! 51 | owner: Account! 52 | ownershipTransferred: [OwnershipTransferred!]! @derivedFrom(field: "contract") 53 | } 54 | type OwnershipTransferred implements Event @entity { 55 | id: ID! 56 | transaction: Transaction! 57 | timestamp: BigInt! 58 | contract: Ownable! 59 | owner: Account! 60 | } 61 | interface Event { 62 | id: ID! 63 | transaction: Transaction! 64 | timestamp: BigInt! 65 | } 66 | type Transaction @entity { 67 | id: ID! 68 | timestamp: BigInt! 69 | blockNumber: BigInt! 70 | events: [Event!]! @derivedFrom(field: "transaction") 71 | } 72 | -------------------------------------------------------------------------------- /generated/subgraph.yaml: -------------------------------------------------------------------------------- 1 | specVersion: 0.0.2 2 | schema: 3 | file: sample.schema.graphql 4 | dataSources: 5 | - kind: ethereum/contract 6 | name: erc721 7 | network: mainnet 8 | source: 9 | address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8" 10 | abi: IERC721 11 | startBlock: 12878203 12 | mapping: 13 | kind: ethereum/events 14 | apiVersion: 0.0.4 15 | language: wasm/assemblyscript 16 | entities: 17 | - ERC721Contract 18 | abis: 19 | - name: IERC721 20 | file: ../node_modules/@openzeppelin/contracts/build/contracts/IERC721Metadata.json 21 | eventHandlers: 22 | - event: Approval(indexed address,indexed address,indexed uint256) 23 | handler: handleApproval 24 | - event: ApprovalForAll(indexed address,indexed address,bool) 25 | handler: handleApprovalForAll 26 | - event: Transfer(indexed address,indexed address,indexed uint256) 27 | handler: handleTransfer 28 | file: ../node_modules/@openzeppelin/subgraphs/src/datasources/erc721.ts 29 | - kind: ethereum/contract 30 | name: ownable 31 | network: mainnet 32 | source: 33 | address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8" 34 | abi: Ownable 35 | startBlock: 12878203 36 | mapping: 37 | kind: ethereum/events 38 | apiVersion: 0.0.4 39 | language: wasm/assemblyscript 40 | entities: 41 | - Ownable 42 | abis: 43 | - name: Ownable 44 | file: ../node_modules/@openzeppelin/contracts/build/contracts/Ownable.json 45 | eventHandlers: 46 | - event: OwnershipTransferred(indexed address,indexed address) 47 | handler: handleOwnershipTransferred 48 | file: ../node_modules/@openzeppelin/subgraphs/src/datasources/ownable.ts 49 | - kind: ethereum/contract 50 | name: erc721-2 51 | network: mainnet 52 | source: 53 | address: "0x1a92f7381b9f03921564a437210bb9396471050c" 54 | abi: IERC721 55 | startBlock: 12743024 56 | mapping: 57 | kind: ethereum/events 58 | apiVersion: 0.0.4 59 | language: wasm/assemblyscript 60 | entities: 61 | - ERC721Contract 62 | abis: 63 | - name: IERC721 64 | file: ../node_modules/@openzeppelin/contracts/build/contracts/IERC721Metadata.json 65 | eventHandlers: 66 | - event: Approval(indexed address,indexed address,indexed uint256) 67 | handler: handleApproval 68 | - event: ApprovalForAll(indexed address,indexed address,bool) 69 | handler: handleApprovalForAll 70 | - event: Transfer(indexed address,indexed address,indexed uint256) 71 | handler: handleTransfer 72 | file: ../node_modules/@openzeppelin/subgraphs/src/datasources/erc721.ts 73 | - kind: ethereum/contract 74 | name: ownable-3 75 | network: mainnet 76 | source: 77 | address: "0x1a92f7381b9f03921564a437210bb9396471050c" 78 | abi: Ownable 79 | startBlock: 12743024 80 | mapping: 81 | kind: ethereum/events 82 | apiVersion: 0.0.4 83 | language: wasm/assemblyscript 84 | entities: 85 | - Ownable 86 | abis: 87 | - name: Ownable 88 | file: ../node_modules/@openzeppelin/contracts/build/contracts/Ownable.json 89 | eventHandlers: 90 | - event: OwnershipTransferred(indexed address,indexed address) 91 | handler: handleOwnershipTransferred 92 | file: ../node_modules/@openzeppelin/subgraphs/src/datasources/ownable.ts 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nft-api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@openzeppelin/subgraphs": "^0.1.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sluganddeploykey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/openzeppelin-nft-api/1b44ca2901949b26037b405009bf892b8027307a/sluganddeploykey.png -------------------------------------------------------------------------------- /subgraphconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": "generated/", 3 | "chain": "mainnet", 4 | "datasources": [ 5 | { "address": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", "startBlock": 12878203, "module": [ "erc721", "ownable" ] }, 6 | { "address": "0x1a92f7381b9f03921564a437210bb9396471050c", "startBlock": 12743024, "module": [ "erc721", "ownable" ] } 7 | ] 8 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@amxx/graphprotocol-utils@^1.0.0-alpha.11": 6 | version "1.0.0-alpha.12" 7 | resolved "https://registry.yarnpkg.com/@amxx/graphprotocol-utils/-/graphprotocol-utils-1.0.0-alpha.12.tgz#b839a758d8304e04db85a95144b8274ebd99be78" 8 | integrity sha512-41y99o/buimY1iCHLujBlkwJjXZNXTM+H4b1lQzc2ofUJLe0NECIQPMwpExC87mOgKEuPlQHEAVEPISKEwjL2Q== 9 | dependencies: 10 | "@graphprotocol/graph-ts" "^0.20.0" 11 | yargs "^17.0.1" 12 | 13 | "@graphprotocol/graph-ts@^0.20.0": 14 | version "0.20.0" 15 | resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.20.0.tgz#ed31ffd59a6aa9703a1ec5079f137a81220443cb" 16 | integrity sha512-+R0Tu/MD4Fiq0Fo+v1l+xznz+ZrciQKWlzMtXjDrhM70vlMNVL9wDmf90MVFYpslgqIfw024hT6XwlmyNyOWbQ== 17 | dependencies: 18 | assemblyscript "https://github.com/AssemblyScript/assemblyscript#36040d5b5312f19a025782b5e36663823494c2f3" 19 | 20 | "@openzeppelin/contracts@^4.3.0-rc.0": 21 | version "4.3.0" 22 | resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.0.tgz#345236d4ec73ef381ab4907c6ef66fd55e5dedad" 23 | integrity sha512-+uBDl/TrmR0Kch6mq3tuxMex/fK7huR6+fQMae+zJk1K5T+dp0pFl12Hbc+1L6oYMXoyDSBJ8zqhRIntrREDFA== 24 | 25 | "@openzeppelin/subgraphs@^0.1.2": 26 | version "0.1.2" 27 | resolved "https://registry.yarnpkg.com/@openzeppelin/subgraphs/-/subgraphs-0.1.2.tgz#f8b2bdbe6955a8a8f60ff1363b067d01852d87b9" 28 | integrity sha512-iRu9IlU53wqWYPtwHq9W182IbUwRRXxZMa6dhrAJqLWox60ic7qxoN/yN94rT5xCrRfQsnLyKSOC98FnaPesOQ== 29 | dependencies: 30 | "@amxx/graphprotocol-utils" "^1.0.0-alpha.11" 31 | "@openzeppelin/contracts" "^4.3.0-rc.0" 32 | 33 | "@protobufjs/utf8@^1.1.0": 34 | version "1.1.0" 35 | resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" 36 | integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= 37 | 38 | ansi-regex@^5.0.0: 39 | version "5.0.0" 40 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 41 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 42 | 43 | ansi-styles@^4.0.0: 44 | version "4.3.0" 45 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 46 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 47 | dependencies: 48 | color-convert "^2.0.1" 49 | 50 | "assemblyscript@git+https://github.com/AssemblyScript/assemblyscript.git#36040d5b5312f19a025782b5e36663823494c2f3": 51 | version "0.6.0" 52 | resolved "git+https://github.com/AssemblyScript/assemblyscript.git#36040d5b5312f19a025782b5e36663823494c2f3" 53 | dependencies: 54 | "@protobufjs/utf8" "^1.1.0" 55 | binaryen "77.0.0-nightly.20190407" 56 | glob "^7.1.3" 57 | long "^4.0.0" 58 | opencollective-postinstall "^2.0.0" 59 | source-map-support "^0.5.11" 60 | 61 | balanced-match@^1.0.0: 62 | version "1.0.2" 63 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 64 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 65 | 66 | binaryen@77.0.0-nightly.20190407: 67 | version "77.0.0-nightly.20190407" 68 | resolved "https://registry.yarnpkg.com/binaryen/-/binaryen-77.0.0-nightly.20190407.tgz#fbe4f8ba0d6bd0809a84eb519d2d5b5ddff3a7d1" 69 | integrity sha512-1mxYNvQ0xywMe582K7V6Vo2zzhZZxMTeGHH8aE/+/AND8f64D8Q1GThVY3RVRwGY/4p+p95ccw9Xbw2ovFXRIg== 70 | 71 | brace-expansion@^1.1.7: 72 | version "1.1.11" 73 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 74 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 75 | dependencies: 76 | balanced-match "^1.0.0" 77 | concat-map "0.0.1" 78 | 79 | buffer-from@^1.0.0: 80 | version "1.1.2" 81 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 82 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 83 | 84 | cliui@^7.0.2: 85 | version "7.0.4" 86 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 87 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 88 | dependencies: 89 | string-width "^4.2.0" 90 | strip-ansi "^6.0.0" 91 | wrap-ansi "^7.0.0" 92 | 93 | color-convert@^2.0.1: 94 | version "2.0.1" 95 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 96 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 97 | dependencies: 98 | color-name "~1.1.4" 99 | 100 | color-name@~1.1.4: 101 | version "1.1.4" 102 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 103 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 104 | 105 | concat-map@0.0.1: 106 | version "0.0.1" 107 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 108 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 109 | 110 | emoji-regex@^8.0.0: 111 | version "8.0.0" 112 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 113 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 114 | 115 | escalade@^3.1.1: 116 | version "3.1.1" 117 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 118 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 119 | 120 | fs.realpath@^1.0.0: 121 | version "1.0.0" 122 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 123 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 124 | 125 | get-caller-file@^2.0.5: 126 | version "2.0.5" 127 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 128 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 129 | 130 | glob@^7.1.3: 131 | version "7.1.7" 132 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" 133 | integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== 134 | dependencies: 135 | fs.realpath "^1.0.0" 136 | inflight "^1.0.4" 137 | inherits "2" 138 | minimatch "^3.0.4" 139 | once "^1.3.0" 140 | path-is-absolute "^1.0.0" 141 | 142 | inflight@^1.0.4: 143 | version "1.0.6" 144 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 145 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 146 | dependencies: 147 | once "^1.3.0" 148 | wrappy "1" 149 | 150 | inherits@2: 151 | version "2.0.4" 152 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 153 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 154 | 155 | is-fullwidth-code-point@^3.0.0: 156 | version "3.0.0" 157 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 158 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 159 | 160 | long@^4.0.0: 161 | version "4.0.0" 162 | resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" 163 | integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== 164 | 165 | minimatch@^3.0.4: 166 | version "3.0.4" 167 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 168 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 169 | dependencies: 170 | brace-expansion "^1.1.7" 171 | 172 | once@^1.3.0: 173 | version "1.4.0" 174 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 175 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 176 | dependencies: 177 | wrappy "1" 178 | 179 | opencollective-postinstall@^2.0.0: 180 | version "2.0.3" 181 | resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" 182 | integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== 183 | 184 | path-is-absolute@^1.0.0: 185 | version "1.0.1" 186 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 187 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 188 | 189 | require-directory@^2.1.1: 190 | version "2.1.1" 191 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 192 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 193 | 194 | source-map-support@^0.5.11: 195 | version "0.5.19" 196 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" 197 | integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== 198 | dependencies: 199 | buffer-from "^1.0.0" 200 | source-map "^0.6.0" 201 | 202 | source-map@^0.6.0: 203 | version "0.6.1" 204 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 205 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 206 | 207 | string-width@^4.1.0, string-width@^4.2.0: 208 | version "4.2.2" 209 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" 210 | integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== 211 | dependencies: 212 | emoji-regex "^8.0.0" 213 | is-fullwidth-code-point "^3.0.0" 214 | strip-ansi "^6.0.0" 215 | 216 | strip-ansi@^6.0.0: 217 | version "6.0.0" 218 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 219 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 220 | dependencies: 221 | ansi-regex "^5.0.0" 222 | 223 | wrap-ansi@^7.0.0: 224 | version "7.0.0" 225 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 226 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 227 | dependencies: 228 | ansi-styles "^4.0.0" 229 | string-width "^4.1.0" 230 | strip-ansi "^6.0.0" 231 | 232 | wrappy@1: 233 | version "1.0.2" 234 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 235 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 236 | 237 | y18n@^5.0.5: 238 | version "5.0.8" 239 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 240 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 241 | 242 | yargs-parser@^20.2.2: 243 | version "20.2.9" 244 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 245 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 246 | 247 | yargs@^17.0.1: 248 | version "17.1.1" 249 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" 250 | integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== 251 | dependencies: 252 | cliui "^7.0.2" 253 | escalade "^3.1.1" 254 | get-caller-file "^2.0.5" 255 | require-directory "^2.1.1" 256 | string-width "^4.2.0" 257 | y18n "^5.0.5" 258 | yargs-parser "^20.2.2" 259 | --------------------------------------------------------------------------------