
掌握API建模:基本概念和實踐
# or
$ yarn global add @graphprotocol/graph-cli
安裝Graph CLI后,您可以使用Graph CLIinit命令初始化一個新的子圖。
兩種方法:
1 從示例子圖中
$ graph init --from-example <GITHUB_USERNAME>/<SUBGRAPH_NAME> [<DIRECTORY>]
2 來自現有的智能合約
如果您已經將智能合約部署到以太坊主網或測試網之一,則從該合約初始化新的子圖是啟動和運行的簡便方法。
$ graph init --from-contract <CONTRACT_ADDRESS> \
[--network <ETHEREUM_NETWORK>] \
[--abi <FILE>] \
<GITHUB_USER>/<SUBGRAPH_NAME> [<DIRECTORY>]
在我們的例子中,我們將使用Zora令牌合約,因此我們可以通過使用–from-contract標志傳遞合約地址來從該合約地址進行初始化:
$ graph init --from-contract 0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7 --network mainnet \
--contract-name Token --index-events
? Subgraph name ? your-username/Zoranftsubgraph
? Directory to create the subgraph in ? Zoranftsubgraph
? Ethereum network ? Mainnet
? Contract address ? 0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7
? Contract Name · Token
此命令將根據作為參數傳入的合同地址生成一個基本子圖–from-contract。通過使用此合同地址,CLI將在項目中初始化一些內容以幫助您入門。
子圖的主要配置和定義位于subgraph.yaml文件中,子圖代碼庫由幾個文件組成:
我們將使用的subgraph.yaml中的條目是:
使用The Graph,您可以在schema.graphql中定義實體類型,并且Graph Node將生成用于查詢該實體類型的單個實例和集合的頂級字段。每種應為實體的類型都必須使用@entity指令進行注釋。
我們將要建立索引的實體/數據是Token和User。這樣,我們可以索引用戶以及用戶自己創建的令牌。
為此,請使用以下代碼更新schema.graphql:
type Token @entity {
id: ID!
tokenID: BigInt!
contentURI: String!
metadataURI: String!
creator: User!
owner: User!
}
type User @entity {
id: ID!
tokens: [Token!]! @derivedFrom(field: "owner")
created: [Token!]! @derivedFrom(field: "creator")
}
可以通過@derivedFrom字段在實體上定義反向查找。這會在實體上創建一個虛擬字段,可以查詢該虛擬字段,但無法通過映射API手動設置。
相反,它是從另一個實體上定義的關系派生的。對于此類關系,存儲關系的兩邊幾乎沒有意義,并且僅存儲一側而派生另一側時,索引和查詢性能都將更好。
現在,我們已經為我們的應用程序創建了GraphQL模式,我們可以在本地生成實體,以開始在mappingsCLI所創建的實體中使用:
graph codegen
為了使工作中的智能合約,事件和實體變得容易且類型安全,Graph CLI從子圖的GraphQL模式和數據源中包含的合約ABI的組合中生成AssemblyScript類型。
現在,我們可以配置subgraph.yaml以使用我們剛剛創建的實體并配置它們的映射。
為此,請先dataSources.mapping.entities使用User和Token實體更新字段:
entities:
- Token
- User
接下來,更新,dataSources.mapping.eventHandlers使其僅包括以下兩個事件處理程序:
eventHandlers:
- event: TokenURIUpdated(indexed uint256,address,string)
handler: handleTokenURIUpdated
- event: Transfer(indexed address,indexed address,indexed uint256)
handler: handleTransfer
最后,更新配置以添加startBlock:
source:
address: "0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7"
abi: Token
startBlock: 11565020
接下來,打開src / mappings.ts來編寫我們在子圖subgraph中定義的映射eventHandlers。
使用以下代碼更新文件:
import {
TokenURIUpdated as TokenURIUpdatedEvent,
Transfer as TransferEvent,
Token as TokenContract
} from "../generated/Token/Token"
import {
Token, User
} from '../generated/schema'
export function handleTokenURIUpdated(event: TokenURIUpdatedEvent): void {
let token = Token.load(event.params._tokenId.toString());
token.contentURI = event.params._uri;
token.save();
}
export function handleTransfer(event: TransferEvent): void {
let token = Token.load(event.params.tokenId.toString());
if (!token) {
token = new Token(event.params.tokenId.toString());
token.creator = event.params.to.toHexString();
token.tokenID = event.params.tokenId;
let tokenContract = TokenContract.bind(event.address);
token.contentURI = tokenContract.tokenURI(event.params.tokenId);
token.metadataURI = tokenContract.tokenMetadataURI(event.params.tokenId);
}
token.owner = event.params.to.toHexString();
token.save();
let user = User.load(event.params.to.toHexString());
if (!user) {
user = new User(event.params.to.toHexString());
user.save();
}
}
接下來,讓我們運行一個構建以確保正確配置了所有內容。為此,請運行以下build命令:
$ graph build
如果構建成功,則應該在根目錄中看到一個新的構建文件夾。
要進行部署,我們可以deploy使用Graph CLI運行該命令。要進行部署,您首先需要為在Graph Explorer中創建的子圖復制Access令牌:
接下來,運行以下命令:
$ graph auth https://api.thegraph.com/deploy/ <ACCESS_TOKEN>
$ yarn deploy
部署子圖后,您應該看到它顯示在您的儀表板中:
當您單擊子圖時,它應該打開Graph資源管理器:
現在我們位于儀表板中,我們應該能夠開始查詢數據了。運行以下查詢以獲取令牌及其元數據的列表:
{
tokens {
id
tokenID
contentURI
metadataURI
}
}
我們還可以配置訂單方向:
{
tokens(
orderBy:id,
orderDirection: desc
) {
id
tokenID
contentURI
metadataURI
}
}
或選擇跳過某些結果以實現一些基本分頁:
{
tokens(
skip: 100,
orderBy:id,
orderDirection: desc
) {
id
tokenID
contentURI
metadataURI
}
}
或查詢用戶及其相關內容:
{
users {
id
tokens {
id
contentURI
}
}
}
如果我們想要對子圖進行一些更改然后重新部署,我們應該怎么辦?假設我們要向子圖添加新功能,假設我們除了現有的查詢功能外,還想添加該功能以按創建NFT的時間戳進行排序。
為此,我們需要先向實體添加一個新createdAtTimestamp字段Token:
type Token @entity {
id: ID!
tokenID: BigInt!
contentURI: String!
metadataURI: String!
creator: User!
owner: User!
"Add new createdAtTimesamp field"
createdAtTimestamp: BigInt!
}
現在,我們可以重新運行代碼生成:
graph codegen
接下來,我們需要更新映射以保存此新字段:
// update the handleTransfer function to add the createdAtTimestamp to the token object
export function handleTransfer(event: TransferEvent): void {
let token = Token.load(event.params.tokenId.toString());
if (!token) {
token = new Token(event.params.tokenId.toString());
token.creator = event.params.to.toHexString();
token.tokenID = event.params.tokenId;
// Add the createdAtTimestamp to the token object
token.createdAtTimestamp = event.block.timestamp;
let tokenContract = TokenContract.bind(event.address);
token.contentURI = tokenContract.tokenURI(event.params.tokenId);
token.metadataURI = tokenContract.tokenMetadataURI(event.params.tokenId);
}
token.owner = event.params.to.toHexString();
token.save();
let user = User.load(event.params.to.toHexString());
if (!user) {
user = new User(event.params.to.toHexString());
user.save();
}
}
現在我們可以重新部署子圖:
$ yarn deploy
子圖重新部署后,我們現在可以按時間戳查詢以查看最近創建的NFTS:
{
tokens(
orderBy:createdAtTimestamp,
orderDirection: desc
) {
id
tokenID
contentURI
metadataURI
}
}}
文章轉自微信公眾號@區塊鏈研究實驗室