Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
GOLDSKY_API_KEY=
GOLDSKY_API_KEY=
GRAPH_DEPLOY_KEY=
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@
"test:e2e:ci": "cd tests/e2e && GRAPH_NODE_BASE_IMAGE=graphprotocol/graph-node:latest docker compose -f docker-compose.yml -f docker-compose.ci.yml up --exit-code-from runner",
"run:local": "cd tests/e2e && GRAPH_NODE_BASE_IMAGE=graph-node:latest docker compose -f docker-compose.yml -f docker-compose.local.yml up",
"coverage": "graph test -- -c",
"deploy:studio": "yarn prepare:mainnet && graph deploy --studio art-blocks",
"deploy:studio-base": "yarn prepare:base && graph deploy --studio art-blocks-base",
"deploy:studio-sepolia-dev": "yarn prepare:sepolia-dev && graph deploy --studio art-blocks-dev-sepolia",
"deploy:studio-sepolia-staging": "yarn prepare:sepolia-staging && graph deploy --studio art-blocks-staging-sepolia",
"deploy:studio-arbitrum-one": "yarn prepare:arbitrum-one && graph deploy --studio art-blocks-arbitrum",
"deploy:studio": "yarn prepare:mainnet && source .env && yarn graph deploy --studio art-blocks --deploy-key=$GRAPH_DEPLOY_KEY",
"deploy:studio-base": "yarn prepare:base && source .env && yarn graph deploy --studio art-blocks-base --deploy-key=$GRAPH_DEPLOY_KEY",
"deploy:studio-arbitrum-one": "yarn prepare:arbitrum-one && source .env && yarn graph deploy --studio art-blocks-arbitrum --deploy-key=$GRAPH_DEPLOY_KEY",
"deploy:goldsky-sepolia-dev": "sh -c 'read -p \"Enter subgraph version: \" version; if [ -z \"$version\" ]; then echo \"Version is required\" >&2; exit 1; fi; yarn prepare:sepolia-dev && graph build && set -a && source .env && set +a && goldsky login --token \"$GOLDSKY_API_KEY\" && goldsky subgraph deploy artblocks-sepolia-dev/\"$version\"'",
"deploy:goldsky-sepolia-staging": "sh -c 'read -p \"Enter subgraph version: \" version; if [ -z \"$version\" ]; then echo \"Version is required\" >&2; exit 1; fi; yarn prepare:sepolia-staging && graph build && set -a && source .env && set +a && goldsky login --token \"$GOLDSKY_API_KEY\" && goldsky subgraph deploy artblocks-sepolia-staging/\"$version\"'",
"tag-latest:goldsky-sepolia-dev": "sh -c 'read -p \"Enter dev subgraph version you want to tag as latest: \" version; if [ -z \"$version\" ]; then echo \"Version is required\" >&2; exit 1; fi; source .env && set +a && goldsky login --token \"$GOLDSKY_API_KEY\" && goldsky subgraph tag create artblocks-sepolia-dev/\"$version\" --tag latest'",
Expand All @@ -30,7 +28,8 @@
"prepare:local": "yarn codegen:generic && mustache config/local.json subgraph.template.yaml > subgraph.yaml",
"prepare:generic": "yarn codegen:generic",
"codegen:generic": "yarn generate:abis && mkdir -p ./generated && rm -r ./generated && mustache config/generic.json subgraph.template.yaml > subgraph.yaml && graph codegen",
"generate:abis": "cd ./abis && ./_generate-abis.sh && cd ../"
"generate:abis": "cd ./abis && ./_generate-abis.sh && cd ../",
"postinstall": "patch-package"
},
"dependencies": {
"@artblocks/contracts": "1.3.2",
Expand All @@ -41,6 +40,8 @@
},
"devDependencies": {
"assemblyscript": "^0.19.22",
"mustache": "^4.1.0"
"mustache": "^4.1.0",
"patch-package": "^8.0.1",
"postinstall-postinstall": "^2.1.0"
}
}
71 changes: 71 additions & 0 deletions patches/@graphprotocol+graph-cli+0.56.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
diff --git a/node_modules/@graphprotocol/graph-cli/dist/compiler/index.js b/node_modules/@graphprotocol/graph-cli/dist/compiler/index.js
index a53b2a0..71b032f 100644
--- a/node_modules/@graphprotocol/graph-cli/dist/compiler/index.js
+++ b/node_modules/@graphprotocol/graph-cli/dist/compiler/index.js
@@ -480,6 +480,10 @@ class Compiler {
const uploadCacheKey = this.cacheKeyForFile(absoluteFile);
const alreadyUploaded = uploadedFiles.has(uploadCacheKey);
if (!alreadyUploaded) {
+ // Throttle uploads: wait 250ms between each new upload to avoid rate limits
+ if (uploadedFiles.size > 0) {
+ await new Promise(resolve => setTimeout(resolve, 250));
+ }
// @ts-expect-error Buffer.from with Buffer data can indeed accept utf-8
const content = Buffer.from(await fs_extra_1.default.readFile(absoluteFile), 'utf-8');
const hash = await this._uploadToIPFS({
@@ -497,20 +501,41 @@ class Compiler {
const file = { path: 'subgraph.yaml', content: Buffer.from(str, 'utf-8') };
return await this._uploadToIPFS(file);
}
- async _uploadToIPFS(file) {
- try {
- const files = this.ipfs.addAll([file]);
- // We get back async iterable
- const filesIterator = files[Symbol.asyncIterator]();
- // We only care about the first item, since that is the file, rest could be directories
- const { value } = await filesIterator.next();
- // we grab the file and pin it
- const uploadedFile = value;
- await this.ipfs.pin.add(uploadedFile.cid);
- return uploadedFile.cid.toString();
- }
- catch (e) {
- throw Error(`Failed to upload file to IPFS: ${e.message}`);
+ _isRateLimitError(message) {
+ return message && (message.includes('1015') || message.includes('rate limit') || message.includes('Rate limit') || message.includes('banned you temporarily') || message.includes('Access denied'));
+ }
+ async _uploadToIPFS(file, retries = 8) {
+ for (let attempt = 1; attempt <= retries; attempt++) {
+ try {
+ const files = this.ipfs.addAll([file]);
+ // We get back async iterable
+ const filesIterator = files[Symbol.asyncIterator]();
+ // We only care about the first item, since that is the file, rest could be directories
+ const { value } = await filesIterator.next();
+ // we grab the file and pin it
+ const uploadedFile = value;
+ await this.ipfs.pin.add(uploadedFile.cid);
+ return uploadedFile.cid.toString();
+ }
+ catch (e) {
+ if (attempt < retries) {
+ let delay;
+ if (this._isRateLimitError(e.message)) {
+ // Cloudflare rate limit: wait 60-90s for the ban to expire
+ delay = 60000 + Math.random() * 30000;
+ console.warn(`IPFS upload attempt ${attempt}/${retries} rate-limited. Waiting ${Math.round(delay / 1000)}s for rate limit to reset...`);
+ }
+ else {
+ // Other errors: standard exponential backoff (1s, 2s, 4s, 8s...)
+ delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000) + Math.random() * 1000;
+ console.warn(`IPFS upload attempt ${attempt}/${retries} failed: ${e.message}. Retrying in ${Math.round(delay / 1000)}s...`);
+ }
+ await new Promise(resolve => setTimeout(resolve, delay));
+ }
+ else {
+ throw Error(`Failed to upload file to IPFS after ${retries} attempts: ${e.message}`);
+ }
+ }
}
}
}
Loading
Loading