Skip to content

Commit 281c9df

Browse files
committed
chore(subgraph): update subgraph abis / fix(subgraph): add error handling if the metadata is null and deploy a new version for sepolia and mainnet
1 parent 1b3abcd commit 281c9df

File tree

6 files changed

+158
-30
lines changed

6 files changed

+158
-30
lines changed

subgraph/abis/IPToken.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,12 @@
193193
"internalType": "uint256"
194194
},
195195
{
196-
"name": "name",
196+
"name": "name_",
197197
"type": "string",
198198
"internalType": "string"
199199
},
200200
{
201-
"name": "symbol",
201+
"name": "symbol_",
202202
"type": "string",
203203
"internalType": "string"
204204
},

subgraph/abis/TermsAcceptedPermissioner.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{
77
"name": "tokenContract",
88
"type": "address",
9-
"internalType": "contract IPToken"
9+
"internalType": "contract IIPToken"
1010
},
1111
{
1212
"name": "_for",
@@ -29,7 +29,7 @@
2929
{
3030
"name": "tokenContract",
3131
"type": "address",
32-
"internalType": "contract IPToken"
32+
"internalType": "contract IIPToken"
3333
},
3434
{
3535
"name": "signer",
@@ -94,7 +94,7 @@
9494
{
9595
"name": "tokenContract",
9696
"type": "address",
97-
"internalType": "contract IPToken"
97+
"internalType": "contract IIPToken"
9898
}
9999
],
100100
"outputs": [

subgraph/abis/Tokenizer.json

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,40 @@
44
"inputs": [],
55
"stateMutability": "nonpayable"
66
},
7+
{
8+
"type": "function",
9+
"name": "attachIpt",
10+
"inputs": [
11+
{
12+
"name": "ipnftId",
13+
"type": "uint256",
14+
"internalType": "uint256"
15+
},
16+
{
17+
"name": "agreementCid",
18+
"type": "string",
19+
"internalType": "string"
20+
},
21+
{
22+
"name": "signedAgreement",
23+
"type": "bytes",
24+
"internalType": "bytes"
25+
},
26+
{
27+
"name": "tokenContract",
28+
"type": "address",
29+
"internalType": "contract IERC20Metadata"
30+
}
31+
],
32+
"outputs": [
33+
{
34+
"name": "",
35+
"type": "address",
36+
"internalType": "contract IIPToken"
37+
}
38+
],
39+
"stateMutability": "nonpayable"
40+
},
741
{
842
"type": "function",
943
"name": "cap",
@@ -146,6 +180,11 @@
146180
"type": "function",
147181
"name": "reinit",
148182
"inputs": [
183+
{
184+
"name": "_wrappedIpTokenImplementation",
185+
"type": "address",
186+
"internalType": "contract WrappedIPToken"
187+
},
149188
{
150189
"name": "_ipTokenImplementation",
151190
"type": "address",
@@ -175,6 +214,19 @@
175214
"outputs": [],
176215
"stateMutability": "nonpayable"
177216
},
217+
{
218+
"type": "function",
219+
"name": "setWrappedIPTokenImplementation",
220+
"inputs": [
221+
{
222+
"name": "_wrappedIpTokenImplementation",
223+
"type": "address",
224+
"internalType": "contract WrappedIPToken"
225+
}
226+
],
227+
"outputs": [],
228+
"stateMutability": "nonpayable"
229+
},
178230
{
179231
"type": "function",
180232
"name": "synthesized",
@@ -189,7 +241,7 @@
189241
{
190242
"name": "",
191243
"type": "address",
192-
"internalType": "contract IPToken"
244+
"internalType": "contract IIPToken"
193245
}
194246
],
195247
"stateMutability": "view"
@@ -277,6 +329,19 @@
277329
"outputs": [],
278330
"stateMutability": "payable"
279331
},
332+
{
333+
"type": "function",
334+
"name": "wrappedTokenImplementation",
335+
"inputs": [],
336+
"outputs": [
337+
{
338+
"name": "",
339+
"type": "address",
340+
"internalType": "contract WrappedIPToken"
341+
}
342+
],
343+
"stateMutability": "view"
344+
},
280345
{
281346
"type": "event",
282347
"name": "AdminChanged",
@@ -317,13 +382,13 @@
317382
"name": "old",
318383
"type": "address",
319384
"indexed": true,
320-
"internalType": "contract IPToken"
385+
"internalType": "contract IIPToken"
321386
},
322387
{
323388
"name": "_new",
324389
"type": "address",
325390
"indexed": true,
326-
"internalType": "contract IPToken"
391+
"internalType": "contract IIPToken"
327392
}
328393
],
329394
"anonymous": false
@@ -379,6 +444,25 @@
379444
],
380445
"anonymous": false
381446
},
447+
{
448+
"type": "event",
449+
"name": "TokenWrapped",
450+
"inputs": [
451+
{
452+
"name": "tokenContract",
453+
"type": "address",
454+
"indexed": false,
455+
"internalType": "contract IERC20Metadata"
456+
},
457+
{
458+
"name": "wrappedIpt",
459+
"type": "address",
460+
"indexed": false,
461+
"internalType": "contract IIPToken"
462+
}
463+
],
464+
"anonymous": false
465+
},
382466
{
383467
"type": "event",
384468
"name": "TokensCreated",
@@ -447,6 +531,25 @@
447531
],
448532
"anonymous": false
449533
},
534+
{
535+
"type": "event",
536+
"name": "WrappedIPTokenImplementationUpdated",
537+
"inputs": [
538+
{
539+
"name": "old",
540+
"type": "address",
541+
"indexed": true,
542+
"internalType": "contract WrappedIPToken"
543+
},
544+
{
545+
"name": "_new",
546+
"type": "address",
547+
"indexed": true,
548+
"internalType": "contract WrappedIPToken"
549+
}
550+
],
551+
"anonymous": false
552+
},
450553
{
451554
"type": "error",
452555
"name": "AlreadyTokenized",
@@ -457,6 +560,16 @@
457560
"name": "IPTNotControlledByTokenizer",
458561
"inputs": []
459562
},
563+
{
564+
"type": "error",
565+
"name": "InvalidTokenContract",
566+
"inputs": []
567+
},
568+
{
569+
"type": "error",
570+
"name": "InvalidTokenDecimals",
571+
"inputs": []
572+
},
460573
{
461574
"type": "error",
462575
"name": "MustControlIpnft",

subgraph/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"build:sepolia": "graph codegen && graph build --network sepolia",
99
"build:mainnet": "graph codegen && graph build --network mainnet",
1010
"deploy:local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 moleculeprotocol/ipnft-subgraph",
11-
"deploy:sepolia": "env-cmd -x -f ../.env graph deploy ip-nft-sepolia --version-label 1.3.1 --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz --deploy-key \\$SATSUMA_DEPLOY_KEY",
12-
"deploy:mainnet": "env-cmd -x -f ../.env graph deploy ip-nft-mainnet --version-label 1.3.1 --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz --deploy-key \\$SATSUMA_DEPLOY_KEY",
11+
"deploy:sepolia": "env-cmd -x -f ../.env graph deploy ip-nft-sepolia --version-label 1.3.2 --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz --deploy-key \\$SATSUMA_DEPLOY_KEY",
12+
"deploy:mainnet": "env-cmd -x -f ../.env graph deploy ip-nft-mainnet --version-label 1.3.2 --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz --deploy-key \\$SATSUMA_DEPLOY_KEY",
1313
"create:local": "graph create --node http://localhost:8020/ moleculeprotocol/ipnft-subgraph",
1414
"remove:local": "graph remove --node http://localhost:8020/ moleculeprotocol/ipnft-subgraph",
1515
"test": "graph test"

subgraph/src/metadataMapping.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
1-
import { json, Bytes, dataSource, log } from '@graphprotocol/graph-ts'
1+
import { json, Bytes, dataSource, log, JSONValue } from '@graphprotocol/graph-ts'
22
import { IpnftMetadata } from '../generated/schema'
33

44
export function handleMetadata(content: Bytes): void {
5-
const value = json.fromBytes(content).toObject()
6-
if (value) {
7-
const image = value.get('image')
8-
const name = value.get('name')
9-
const description = value.get('description')
10-
const externalURL = value.get('external_url')
5+
// Validate that content is not empty
6+
if (content.length == 0) {
7+
log.warning('[handleMetadata] Empty content received for {}', [dataSource.stringParam()])
8+
return
9+
}
10+
11+
// Check if content looks like JSON (starts with { or [)
12+
if (content[0] != 123 && content[0] != 91) { // 123 = '{', 91 = '['
13+
log.warning('[handleMetadata] Content does not appear to be JSON for {}. First bytes: {}', [
14+
dataSource.stringParam(),
15+
content.toHexString().slice(0, 20)
16+
])
17+
return
18+
}
19+
20+
// Try to parse JSON with error handling
21+
let value = json.try_fromBytes(content)
22+
if (value.isError) {
23+
log.error('[handleMetadata] Failed to parse JSON for {}: {}', [
24+
dataSource.stringParam(),
25+
value.value.toString()
26+
])
27+
return
28+
}
29+
30+
let parsedValue = value.value.toObject()
31+
if (parsedValue) {
32+
const image = parsedValue.get('image')
33+
const name = parsedValue.get('name')
34+
const description = parsedValue.get('description')
35+
const externalURL = parsedValue.get('external_url')
1136

1237
let ipnftMetadata = new IpnftMetadata(dataSource.stringParam())
1338

@@ -22,7 +47,7 @@ export function handleMetadata(content: Bytes): void {
2247
log.info("[handlemetadata] name, image, description, external_url not found", [])
2348
}
2449

25-
let _properties = value.get('properties')
50+
let _properties = parsedValue.get('properties')
2651
if (_properties) {
2752
let properties = _properties.toObject()
2853
let _initial_symbol = properties.get('initial_symbol')

subgraph/subgraph.yaml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ dataSources:
165165
abi: StakedLockingCrowdSale
166166
address: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1"
167167
startBlock: 0
168-
mapping: &stakedLockingCrowdSaleMapping
168+
mapping:
169169
kind: ethereum/events
170170
apiVersion: 0.0.7
171171
language: wasm/assemblyscript
@@ -178,7 +178,7 @@ dataSources:
178178
file: ./abis/StakedLockingCrowdSale.json
179179
- name: IERC20Metadata
180180
file: ./abis/IERC20Metadata.json
181-
eventHandlers:
181+
eventHandlers:
182182
- event: Started(indexed uint256,indexed
183183
address,(address,address,address,uint256,uint256,uint64,address),(address,address,uint256),address,uint256,uint256)
184184
handler: handleStartedLegacy
@@ -204,16 +204,6 @@ dataSources:
204204
- event: ClaimedAuctionTokens(indexed uint256)
205205
handler: handleClaimedFailedSale
206206
file: ./src/stakedLockingCrowdSaleMapping.ts
207-
# in case you need to watch another crowdsale contract this is how it could work:
208-
# - kind: ethereum/contract
209-
# name: StakedLockingCrowdSale2
210-
# network: foundry
211-
# source:
212-
# abi: StakedLockingCrowdSale
213-
# address: "0xbaadf00dbaadf00dbaadf00dbaadf00dbaadf00d"
214-
# startBlock: 0
215-
# mapping: *stakedLockingCrowdSaleMapping
216-
217207
- kind: ethereum/contract
218208
name: TermsAcceptedPermissioner
219209
network: foundry

0 commit comments

Comments
 (0)