Repository: graphprotocol/graph-tooling (ts)

Issue:
`graph init`: contract name with whitespace
i.e. `0x16C6521Dff6baB339122a0FE25a9116693265353` on mainnet

whitespace in contract name `CurveRouter v1_1` causes `graph codegen` to fail:

```
✔ Network · Ethereum Mainnet · mainnet · https://etherscan.io
✔ Source · Smart Contract · ethereum
✔ Subgraph slug · asdf
✔ Directory to create the subgraph in · asdf
✔ Contract address · 0x16C6521Dff6baB339122a0FE25a9116693265353
✔ Fetching ABI from contract API...
✔ Fetching start block from contract API...
✔ Fetching contract name from contract API...
✔ Start block · 20189560
✔ Contract name · CurveRouter v1.1
✔ Index contract events as entities (Y/n) · true
  Generate subgraph
  Write subgraph to directory
✔ Create subgraph scaffold
✔ Initialize networks config
✔ Install dependencies with yarn
✖ Failed to generate code from ABI and GraphQL schema: Command failed: yarn codegen
warning ../../../../package.json: No license field
- Apply migrations
✔ Apply migrations
- Load subgraph from subgraph.yaml
✔ Load subgraph from subgraph.yaml
- Load contract ABIs
  Load contract ABI from abis/CurveRouter v1.1.json
- Load contract ABIs
✔ Load contract ABIs
- Generate types for contract ABIs
  Generate types for contract ABI: CurveRouter v1.1 (abis/CurveRouter v1.1.json)
- Generate types for contract ABIs
✖ Failed to generate types for contract ABIs: Failed to generate types for contract ABI: '{' expected. (59:26)
  57 |
  58 |
> 59 | export class CurveRouter v1_1 extends ethereum.SmartContract {
     |                          ^
  60 |
  61 |
  62 |   static bind(address: Address): CurveRouter v1_1 {
error Command failed with exit code 1.

    Error: Command failed: yarn codegen

```

Let's cleanup the name

Pull request:
`graph init`: invalid characters in contract name
fixes #1883


Patch:
diff --git a/.changeset/@graphprotocol_graph-cli-1834-dependencies.md b/.changeset/@graphprotocol_graph-cli-1834-dependencies.md
deleted file mode 100644
index c4b4c7ae..00000000
--- a/.changeset/@graphprotocol_graph-cli-1834-dependencies.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-"@graphprotocol/graph-cli": patch
----
-dependencies updates:
-  - Updated dependency [`@oclif/core@4.2.4` ↗︎](https://www.npmjs.com/package/@oclif/core/v/4.2.4) (from `4.0.34`, in `dependencies`)
-  - Updated dependency [`chokidar@4.0.3` ↗︎](https://www.npmjs.com/package/chokidar/v/4.0.3) (from `4.0.1`, in `dependencies`)
-  - Updated dependency [`debug@4.4.0` ↗︎](https://www.npmjs.com/package/debug/v/4.4.0) (from `4.3.7`, in `dependencies`)
-  - Updated dependency [`fs-extra@11.3.0` ↗︎](https://www.npmjs.com/package/fs-extra/v/11.3.0) (from `11.2.0`, in `dependencies`)
-  - Updated dependency [`glob@11.0.1` ↗︎](https://www.npmjs.com/package/glob/v/11.0.1) (from `11.0.0`, in `dependencies`)
-  - Updated dependency [`graphql@16.10.0` ↗︎](https://www.npmjs.com/package/graphql/v/16.10.0) (from `16.9.0`, in `dependencies`)
-  - Updated dependency [`undici@7.3.0` ↗︎](https://www.npmjs.com/package/undici/v/7.3.0) (from `7.2.3`, in `dependencies`)
-  - Updated dependency [`yaml@2.7.0` ↗︎](https://www.npmjs.com/package/yaml/v/2.7.0) (from `2.6.1`, in `dependencies`)
diff --git a/.changeset/@graphprotocol_graph-cli-1932-dependencies.md b/.changeset/@graphprotocol_graph-cli-1932-dependencies.md
deleted file mode 100644
index 5f845092..00000000
--- a/.changeset/@graphprotocol_graph-cli-1932-dependencies.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-"@graphprotocol/graph-cli": patch
----
-dependencies updates:
-  - Updated dependency [`@oclif/core@4.2.6` ↗︎](https://www.npmjs.com/package/@oclif/core/v/4.2.6) (from `4.2.4`, in `dependencies`)
-  - Updated dependency [`semver@7.7.1` ↗︎](https://www.npmjs.com/package/semver/v/7.7.1) (from `7.6.3`, in `dependencies`)
diff --git a/.changeset/curly-buses-hang.md b/.changeset/curly-buses-hang.md
deleted file mode 100644
index ef7b1341..00000000
--- a/.changeset/curly-buses-hang.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-cli': minor
----
-
-Add support for subgraph datasource in `graph init`
diff --git a/.changeset/yellow-jobs-brake.md b/.changeset/flat-hairs-study.md
similarity index 50%
rename from .changeset/yellow-jobs-brake.md
rename to .changeset/flat-hairs-study.md
index eb287398..d74b5cfa 100644
--- a/.changeset/yellow-jobs-brake.md
+++ b/.changeset/flat-hairs-study.md
@@ -2,4 +2,4 @@
 '@graphprotocol/graph-cli': patch
 ---
 
-`graph init`: improve error reporting
+handle sized arrays in abi when changetype
diff --git a/.changeset/giant-eyes-play.md b/.changeset/giant-eyes-play.md
deleted file mode 100644
index 40e55821..00000000
--- a/.changeset/giant-eyes-play.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-cli': minor
----
-
-`graph codegen`: handle events with fields with reserved names #1896
diff --git a/.changeset/giant-owls-accept.md b/.changeset/giant-owls-accept.md
deleted file mode 100644
index cbd0815e..00000000
--- a/.changeset/giant-owls-accept.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-cli': patch
----
-
-Use Sourcify v2 endpoint for contract lookups
diff --git a/.changeset/gold-birds-dream.md b/.changeset/gold-birds-dream.md
deleted file mode 100644
index 2d70f85d..00000000
--- a/.changeset/gold-birds-dream.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-cli': patch
----
-
-`graph init`: format and validate subgraph slug to match graph-node rules
diff --git a/.changeset/smooth-poets-rush.md b/.changeset/nervous-garlics-cover.md
similarity index 55%
rename from .changeset/smooth-poets-rush.md
rename to .changeset/nervous-garlics-cover.md
index b7707aec..ee46db8a 100644
--- a/.changeset/smooth-poets-rush.md
+++ b/.changeset/nervous-garlics-cover.md
@@ -2,4 +2,4 @@
 '@graphprotocol/graph-cli': patch
 ---
 
-chore: move github actions around
+show sourcify fetch status
diff --git a/.changeset/new-rules-bake.md b/.changeset/new-rules-bake.md
new file mode 100644
index 00000000..93c2044c
--- /dev/null
+++ b/.changeset/new-rules-bake.md
@@ -0,0 +1,5 @@
+---
+"@graphprotocol/graph-cli": patch
+---
+
+fix: generate types for mappings when int8 is used as id
diff --git a/.changeset/purple-files-think.md b/.changeset/purple-files-think.md
new file mode 100644
index 00000000..9b2864a6
--- /dev/null
+++ b/.changeset/purple-files-think.md
@@ -0,0 +1,5 @@
+---
+'@graphprotocol/graph-cli': patch
+---
+
+`graph codegen`: fix bug with id field clash in example entity
diff --git a/.changeset/rare-carpets-tell.md b/.changeset/rare-carpets-tell.md
deleted file mode 100644
index 37eb11d9..00000000
--- a/.changeset/rare-carpets-tell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-ts': minor
----
-
-feat: add yaml parsing support to mappings
diff --git a/.changeset/red-roses-speak.md b/.changeset/red-roses-speak.md
new file mode 100644
index 00000000..0896dba8
--- /dev/null
+++ b/.changeset/red-roses-speak.md
@@ -0,0 +1,5 @@
+---
+'@graphprotocol/graph-cli': patch
+---
+
+handle invalid characters in contract name #1883
diff --git a/.changeset/witty-teachers-smell.md b/.changeset/witty-teachers-smell.md
deleted file mode 100644
index 989a6067..00000000
--- a/.changeset/witty-teachers-smell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@graphprotocol/graph-cli': patch
----
-
-fix bug with "other wallets" not working #1900
diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md
index 02844f31..5e845742 100644
--- a/packages/cli/CHANGELOG.md
+++ b/packages/cli/CHANGELOG.md
@@ -1,5 +1,43 @@
 # @graphprotocol/graph-cli
 
+## 0.96.0
+
+### Minor Changes
+
+- [#1920](https://github.com/graphprotocol/graph-tooling/pull/1920) [`b6d7f1c`](https://github.com/graphprotocol/graph-tooling/commit/b6d7f1cd149c5784089aa92bafd63e6a0d9814a1) Thanks [@incrypto32](https://github.com/incrypto32)! - Add support for subgraph datasource in `graph init`
+
+- [#1929](https://github.com/graphprotocol/graph-tooling/pull/1929) [`4311d0e`](https://github.com/graphprotocol/graph-tooling/commit/4311d0e177b37a7698d5befae9b6e9cafa6b37c9) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - `graph codegen`: handle events with fields with reserved names #1896
+
+### Patch Changes
+
+- [#1834](https://github.com/graphprotocol/graph-tooling/pull/1834) [`0058157`](https://github.com/graphprotocol/graph-tooling/commit/0058157e45c8902cf0068c359492da3d751529f8) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates:
+
+  - Updated dependency [`@oclif/core@4.2.4` ↗︎](https://www.npmjs.com/package/@oclif/core/v/4.2.4) (from `4.0.34`, in `dependencies`)
+  - Updated dependency [`chokidar@4.0.3` ↗︎](https://www.npmjs.com/package/chokidar/v/4.0.3) (from `4.0.1`, in `dependencies`)
+  - Updated dependency [`debug@4.4.0` ↗︎](https://www.npmjs.com/package/debug/v/4.4.0) (from `4.3.7`, in `dependencies`)
+  - Updated dependency [`fs-extra@11.3.0` ↗︎](https://www.npmjs.com/package/fs-extra/v/11.3.0) (from `11.2.0`, in `dependencies`)
+  - Updated dependency [`glob@11.0.1` ↗︎](https://www.npmjs.com/package/glob/v/11.0.1) (from `11.0.0`, in `dependencies`)
+  - Updated dependency [`graphql@16.10.0` ↗︎](https://www.npmjs.com/package/graphql/v/16.10.0) (from `16.9.0`, in `dependencies`)
+  - Updated dependency [`undici@7.3.0` ↗︎](https://www.npmjs.com/package/undici/v/7.3.0) (from `7.2.3`, in `dependencies`)
+  - Updated dependency [`yaml@2.7.0` ↗︎](https://www.npmjs.com/package/yaml/v/2.7.0) (from `2.6.1`, in `dependencies`)
+
+- [#1932](https://github.com/graphprotocol/graph-tooling/pull/1932) [`80a2ae9`](https://github.com/graphprotocol/graph-tooling/commit/80a2ae9b11260786896665993655056ff048b84b) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates:
+
+  - Updated dependency [`@oclif/core@4.2.6` ↗︎](https://www.npmjs.com/package/@oclif/core/v/4.2.6) (from `4.2.4`, in `dependencies`)
+  - Updated dependency [`semver@7.7.1` ↗︎](https://www.npmjs.com/package/semver/v/7.7.1) (from `7.6.3`, in `dependencies`)
+
+- [#1965](https://github.com/graphprotocol/graph-tooling/pull/1965) [`e7b0e72`](https://github.com/graphprotocol/graph-tooling/commit/e7b0e72610c63dceb1c0af9bd2ef2c14b8bf7609) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - `graph init`: get generated apiVersion and specVersion up to date
+
+- [#1957](https://github.com/graphprotocol/graph-tooling/pull/1957) [`e4af888`](https://github.com/graphprotocol/graph-tooling/commit/e4af88808798e11450b7383d2d658b2ee5936979) Thanks [@0237h](https://github.com/0237h)! - Use Sourcify v2 endpoint for contract lookups
+
+- [#1962](https://github.com/graphprotocol/graph-tooling/pull/1962) [`7f22631`](https://github.com/graphprotocol/graph-tooling/commit/7f226318cf95d959bba2752d9c7d2d518c0622d7) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - `graph init`: format and validate subgraph slug to match graph-node rules
+
+- [#1919](https://github.com/graphprotocol/graph-tooling/pull/1919) [`955f7b0`](https://github.com/graphprotocol/graph-tooling/commit/955f7b02629c142b18ea9f05fce0a6745a4921b7) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - chore: move github actions around
+
+- [#1954](https://github.com/graphprotocol/graph-tooling/pull/1954) [`9fc413f`](https://github.com/graphprotocol/graph-tooling/commit/9fc413f6ba39bf0c4cc36a7683bb13a1157e3606) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - fix bug with "other wallets" not working #1900
+
+- [#1960](https://github.com/graphprotocol/graph-tooling/pull/1960) [`33a7148`](https://github.com/graphprotocol/graph-tooling/commit/33a71482283dd2e578ca02ceb8906e85438e09d0) Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - `graph init`: improve error reporting
+
 ## 0.95.0
 
 ### Minor Changes
diff --git a/packages/cli/package.json b/packages/cli/package.json
index ed5462be..c36b3596 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@graphprotocol/graph-cli",
-  "version": "0.95.0",
+  "version": "0.96.0",
   "type": "module",
   "description": "CLI for building for and deploying to The Graph",
   "repository": {
diff --git a/packages/cli/src/codegen/schema.ts b/packages/cli/src/codegen/schema.ts
index ef98482a..3bbcd5c9 100644
--- a/packages/cli/src/codegen/schema.ts
+++ b/packages/cli/src/codegen/schema.ts
@@ -16,8 +16,9 @@ import * as util from './util.js';
 class IdField {
   static BYTES = Symbol('Bytes');
   static STRING = Symbol('String');
+  static INT8 = Symbol('Int8');
 
-  private kind: typeof IdField.BYTES | typeof IdField.STRING;
+  private kind: typeof IdField.BYTES | typeof IdField.INT8 | typeof IdField.STRING;
 
   constructor(idField: FieldDefinitionNode | undefined) {
     if (idField?.type.kind !== 'NonNullType') {
@@ -27,15 +28,46 @@ class IdField {
       throw Error('id field must be a named type');
     }
     const typeName = idField.type.type.name.value;
-    this.kind = typeName === 'Bytes' ? IdField.BYTES : IdField.STRING;
+    switch (typeName) {
+      case 'Bytes':
+        this.kind = IdField.BYTES;
+        break;
+      case 'Int8':
+        this.kind = IdField.INT8;
+        break;
+      case 'String':
+        this.kind = IdField.STRING;
+        break;
+      default:
+        this.kind = IdField.STRING;
+        break;
+    }
   }
 
   typeName() {
-    return this.kind === IdField.BYTES ? 'Bytes' : 'string';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'Bytes';
+      case IdField.INT8:
+        return 'Int8';
+      case IdField.STRING:
+        return 'string';
+      default:
+        return 'string';
+    }
   }
 
   gqlTypeName() {
-    return this.kind === IdField.BYTES ? 'Bytes' : 'String';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'Bytes';
+      case IdField.INT8:
+        return 'Int8';
+      case IdField.STRING:
+        return 'String';
+      default:
+        return 'String';
+    }
   }
 
   tsNamedType() {
@@ -43,19 +75,55 @@ class IdField {
   }
 
   tsValueFrom() {
-    return this.kind === IdField.BYTES ? 'Value.fromBytes(id)' : 'Value.fromString(id)';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'Value.fromBytes(id)';
+      case IdField.INT8:
+        return 'Value.fromI64(id)';
+      case IdField.STRING:
+        return 'Value.fromString(id)';
+      default:
+        return 'Value.fromString(id)';
+    }
   }
 
   tsValueKind() {
-    return this.kind === IdField.BYTES ? 'ValueKind.BYTES' : 'ValueKind.STRING';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'ValueKind.BYTES';
+      case IdField.INT8:
+        return 'ValueKind.INT8';
+      case IdField.STRING:
+        return 'ValueKind.STRING';
+      default:
+        return 'ValueKind.STRING';
+    }
   }
 
   tsValueToString() {
-    return this.kind == IdField.BYTES ? 'id.toBytes().toHexString()' : 'id.toString()';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'id.toBytes().toHexString()';
+      case IdField.INT8:
+        return 'id.toI64().toString()';
+      case IdField.STRING:
+        return 'id.toString()';
+      default:
+        return 'id.toString()';
+    }
   }
 
   tsToString() {
-    return this.kind == IdField.BYTES ? 'id.toHexString()' : 'id';
+    switch (this.kind) {
+      case IdField.BYTES:
+        return 'id.toHexString()';
+      case IdField.INT8:
+        return 'id.toString()';
+      case IdField.STRING:
+        return 'id';
+      default:
+        return 'id';
+    }
   }
 
   static fromFields(fields: readonly FieldDefinitionNode[] | undefined) {
@@ -92,6 +160,7 @@ export default class SchemaCodeGenerator {
           'Bytes',
           'BigInt',
           'BigDecimal',
+          'Int8',
         ],
         '@graphprotocol/graph-ts',
       ),
diff --git a/packages/cli/src/command-helpers/spinner.ts b/packages/cli/src/command-helpers/spinner.ts
index 7e379ee2..de6eb8e6 100644
--- a/packages/cli/src/command-helpers/spinner.ts
+++ b/packages/cli/src/command-helpers/spinner.ts
@@ -36,7 +36,7 @@ export const withSpinner = async (
   const spinner = print.spin(text);
   try {
     const result = await f(spinner);
-    if (typeof result === 'object') {
+    if (result && typeof result === 'object') {
       const hasError = Object.keys(result).includes('error');
       const hasWarning = Object.keys(result).includes('warning');
       const hasResult = Object.keys(result).includes('result');
diff --git a/packages/cli/src/command-helpers/subgraph.ts b/packages/cli/src/command-helpers/subgraph.ts
index 5ca396db..2a72b58b 100644
--- a/packages/cli/src/command-helpers/subgraph.ts
+++ b/packages/cli/src/command-helpers/subgraph.ts
@@ -9,3 +9,7 @@ export const formatSubgraphName = (slug: string) => {
     .replace(/\s+/g, '-')
     .replace(/[^a-z0-9_-]/g, '');
 };
+
+export const formatContractName = (contractName: string) => {
+  return contractName.replace(/[\s.]+/g, '_').replace(/[^a-zA-Z0-9_-]/g, '');
+};
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
index 9bb408ff..bfc347f1 100644
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -16,7 +16,11 @@ import { retryWithPrompt } from '../command-helpers/retry.js';
 import { generateScaffold, writeScaffold } from '../command-helpers/scaffold.js';
 import { sortWithPriority } from '../command-helpers/sort.js';
 import { withSpinner } from '../command-helpers/spinner.js';
-import { formatSubgraphName, getSubgraphBasename } from '../command-helpers/subgraph.js';
+import {
+  formatContractName,
+  formatSubgraphName,
+  getSubgraphBasename,
+} from '../command-helpers/subgraph.js';
 import { GRAPH_CLI_SHARED_HEADERS } from '../constants.js';
 import debugFactory from '../debug.js';
 import EthereumABI from '../protocols/ethereum/abi.js';
@@ -289,7 +293,7 @@ export default class InitCommand extends Command {
           indexEvents,
           network,
           subgraphName,
-          contractName: contractName || DEFAULT_CONTRACT_NAME,
+          contractName,
           node,
           startBlock,
           spkgPath,
@@ -351,7 +355,7 @@ export default class InitCommand extends Command {
           network: answers.network,
           source: answers.source,
           indexEvents: answers.indexEvents,
-          contractName: answers.contractName || DEFAULT_CONTRACT_NAME,
+          contractName: answers.contractName,
           node,
           startBlock: answers.startBlock,
           spkgPath: answers.spkgPath,
@@ -710,33 +714,34 @@ async function processInitForm(
           return address;
         }
 
-        const sourcifyContractInfo = await contractService.getFromSourcify(
-          EthereumABI,
-          network.id,
-          address,
-        );
-        if (sourcifyContractInfo) {
-          initStartBlock ??= sourcifyContractInfo.startBlock;
-          initContractName ??= sourcifyContractInfo.name;
-          initAbi ??= sourcifyContractInfo.abi;
-          initDebugger.extend('processInitForm')(
-            "infoFromSourcify: '%s'/'%s'",
-            initStartBlock,
-            initContractName,
-          );
-        }
-
-        // If ABI is not provided, try to fetch it from Etherscan API
+        // If ABI is not provided, try to fetch it from Sourcify/Etherscan API
         if (protocolInstance.hasABIs() && !initAbi) {
-          abiFromApi = await retryWithPrompt(() =>
-            withSpinner(
-              'Fetching ABI from contract API...',
-              'Failed to fetch ABI',
-              'Warning fetching ABI',
-              () => contractService.getABI(protocolInstance.getABI(), network.id, address),
-            ),
+          const sourcifyContractInfo = await withSpinner(
+            'Fetching ABI from Sourcify API...',
+            'Failed to fetch ABI',
+            'Warning fetching ABI',
+            () => contractService.getFromSourcify(protocolInstance.getABI(), network.id, address),
           );
-          initDebugger.extend('processInitForm')("abiFromEtherscan len: '%s'", abiFromApi?.name);
+          if (sourcifyContractInfo) {
+            initStartBlock ??= sourcifyContractInfo.startBlock;
+            initContractName ??= sourcifyContractInfo.name;
+            abiFromApi ??= sourcifyContractInfo.abi;
+            initDebugger.extend('processInitForm')(
+              "infoFromSourcify: '%s'/'%s'",
+              initStartBlock,
+              initContractName,
+            );
+          } else {
+            abiFromApi = await retryWithPrompt(() =>
+              withSpinner(
+                'Fetching ABI from Contract API...',
+                'Failed to fetch ABI',
+                'Warning fetching ABI',
+                () => contractService.getABI(protocolInstance.getABI(), network.id, address),
+              ),
+            );
+            initDebugger.extend('processInitForm')("abiFromEtherscan ABI: '%s'", abiFromApi?.name);
+          }
         } else {
           abiFromApi = initAbi;
         }
@@ -745,7 +750,7 @@ async function processInitForm(
         if (!initStartBlock) {
           startBlock = await retryWithPrompt(() =>
             withSpinner(
-              'Fetching start block from contract API...',
+              'Fetching start block from Contract API...',
               'Failed to fetch start block',
               'Warning fetching start block',
               () => contractService.getStartBlock(network.id, address),
@@ -758,7 +763,7 @@ async function processInitForm(
         if (!initContractName) {
           contractName = await retryWithPrompt(() =>
             withSpinner(
-              'Fetching contract name from contract API...',
+              'Fetching contract name from Contract API...',
               'Failed to fetch contract name',
               'Warning fetching contract name',
               () => contractService.getContractName(network.id, address),
@@ -872,7 +877,7 @@ async function processInitForm(
       type: 'input',
       name: 'contractName',
       message: 'Contract name',
-      initial: () => initContractName || contractName || 'Contract',
+      initial: () => initContractName || contractName || DEFAULT_CONTRACT_NAME,
       skip: () => initFromExample !== undefined || !protocolInstance.hasContract() || isSubstreams,
       validate: value =>
         initFromExample !== undefined ||
@@ -1307,7 +1312,7 @@ async function initSubgraphFromContract(
           network,
           source,
           indexEvents,
-          contractName,
+          contractName: formatContractName(contractName || DEFAULT_CONTRACT_NAME),
           startBlock,
           node,
           spkgPath,
diff --git a/packages/cli/src/protocols/ethereum/scaffold/manifest.ts b/packages/cli/src/protocols/ethereum/scaffold/manifest.ts
index 5bfa7d02..e49bc942 100644
--- a/packages/cli/src/protocols/ethereum/scaffold/manifest.ts
+++ b/packages/cli/src/protocols/ethereum/scaffold/manifest.ts
@@ -22,7 +22,7 @@ export const source = ({
 
 export const mapping = ({ abi, contractName }: { abi: ABI; contractName: string }) => `
       kind: ethereum/events
-      apiVersion: 0.0.7
+      apiVersion: 0.0.9
       language: wasm/assemblyscript
       entities:
         ${abiEvents(abi)
diff --git a/packages/cli/src/protocols/subgraph/scaffold/manifest.ts b/packages/cli/src/protocols/subgraph/scaffold/manifest.ts
index 32e4eaad..1acf8f76 100644
--- a/packages/cli/src/protocols/subgraph/scaffold/manifest.ts
+++ b/packages/cli/src/protocols/subgraph/scaffold/manifest.ts
@@ -20,7 +20,7 @@ export const mapping = ({
   contractName: string;
 }) => `
       kind: ethereum/events
-      apiVersion: 0.0.7
+      apiVersion: 0.0.9
       language: wasm/assemblyscript
       entities:
        - ExampleEntity
diff --git a/packages/cli/src/scaffold/index.ts b/packages/cli/src/scaffold/index.ts
index d80c780c..2b9ae634 100644
--- a/packages/cli/src/scaffold/index.ts
+++ b/packages/cli/src/scaffold/index.ts
@@ -20,7 +20,7 @@ const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS
     undefined
   : // For scaffolding real subgraphs
     version;
-const GRAPH_TS_VERSION = '0.36.0';
+const GRAPH_TS_VERSION = '0.37.0';
 const GRAPH_MATCHSTICK_VERSION = '0.6.0';
 
 export interface ScaffoldOptions {
@@ -141,7 +141,7 @@ export default class Scaffold {
 
     return await prettier.format(
       `
-specVersion: 1.0.0
+specVersion: 1.2.0
 indexerHints:
   prune: auto
 schema:
diff --git a/packages/cli/src/scaffold/mapping.ts b/packages/cli/src/scaffold/mapping.ts
index a363f21c..39d7196f 100644
--- a/packages/cli/src/scaffold/mapping.ts
+++ b/packages/cli/src/scaffold/mapping.ts
@@ -15,12 +15,13 @@ export const generateFieldAssignment = (
 ): { assignment: string; imports: string[] } => {
   const safeKey = key.map(k => util.handleReservedWord(k));
   const safeValue = value.map(v => util.handleReservedWord(v));
+  const cleanType = type.replace(/\[\d+\]/g, '[]');
 
   let rightSide = `event.params.${safeValue.join('.')}`;
   const imports = [];
 
-  if (type in VALUE_TYPECAST_MAP) {
-    const castTo = VALUE_TYPECAST_MAP[type];
+  if (cleanType in VALUE_TYPECAST_MAP) {
+    const castTo = VALUE_TYPECAST_MAP[cleanType];
     rightSide = `changetype<${castTo}>(${rightSide})`;
     imports.push(castTo.replace('[]', ''));
   }
diff --git a/packages/cli/src/scaffold/schema.ts b/packages/cli/src/scaffold/schema.ts
index e3b00b9b..9f66b506 100644
--- a/packages/cli/src/scaffold/schema.ts
+++ b/packages/cli/src/scaffold/schema.ts
@@ -89,11 +89,10 @@ export const generateExampleEntityType = (protocol: Protocol, events: any[]) =>
   id: Bytes!
   count: BigInt!
   ${events[0].inputs
-    .reduce(
-      (acc: any[], input: any, index: number) =>
-        acc.concat(generateEventFields({ input, index, protocolName: protocol.name })),
-      [],
-    )
+    .reduce((acc: any[], input: any, index: number) => {
+      input.name = renameNameIfNeeded(input.name);
+      return acc.concat(generateEventFields({ input, index, protocolName: protocol.name }));
+    }, [])
     .slice(0, 2)
     .join('\n')}
 }`;
diff --git a/packages/ts/CHANGELOG.md b/packages/ts/CHANGELOG.md
index 5d90888a..5f964d3c 100644
--- a/packages/ts/CHANGELOG.md
+++ b/packages/ts/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @graphprotocol/graph-ts
 
+## 0.38.0
+
+### Minor Changes
+
+- [#1935](https://github.com/graphprotocol/graph-tooling/pull/1935) [`0c36a02`](https://github.com/graphprotocol/graph-tooling/commit/0c36a024e0516bbf883ae62b8312dba3d9945f04) Thanks [@isum](https://github.com/isum)! - feat: add yaml parsing support to mappings
+
 ## 0.37.0
 
 ### Minor Changes
diff --git a/packages/ts/common/value.ts b/packages/ts/common/value.ts
index ce2a576e..8f7a2959 100644
--- a/packages/ts/common/value.ts
+++ b/packages/ts/common/value.ts
@@ -339,6 +339,14 @@ export class Value {
     return Value.fromArray(output);
   }
 
+  static fromI64Array(input: Array<i64>): Value {
+    const output = new Array<Value>(input.length);
+    for (let i: i64 = 0; i < input.length; i++) {
+      output[i] = Value.fromI64(input[i]);
+    }
+    return Value.fromArray(output);
+  }
+
   static fromBigIntArray(input: Array<BigInt>): Value {
     const output = new Array<Value>(input.length);
     for (let i: i32 = 0; i < input.length; i++) {
diff --git a/packages/ts/package.json b/packages/ts/package.json
index 2750dee4..8a0575ff 100644
--- a/packages/ts/package.json
+++ b/packages/ts/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@graphprotocol/graph-ts",
-  "version": "0.37.0",
+  "version": "0.38.0",
   "description": "TypeScript/AssemblyScript library for writing subgraph mappings for The Graph",
   "repository": {
     "type": "git",


Test patch:
diff --git a/packages/cli/src/codegen/schema.test.ts b/packages/cli/src/codegen/schema.test.ts
index cbf3002c..fd1da33f 100644
--- a/packages/cli/src/codegen/schema.test.ts
+++ b/packages/cli/src/codegen/schema.test.ts
@@ -583,6 +583,134 @@ describe('Schema code generator', { concurrent: true }, () => {
     });
   });
 
+  test('Should handle references with Int8 id types', async () => {
+    const codegen = createSchemaCodeGen(`
+    interface Employee {
+      id: Int8!
+      name: String!
+     }
+
+    type Worker implements Employee @entity {
+      id: Int8!
+      name: String!
+      tasks: [Task!]
+   }
+
+    type Task @entity {
+      id: Int8!
+      employee: Employee!
+      workers: [Worker!] @derivedFrom(field: "tasks")
+      worker: Worker!
+   }
+`);
+
+    const generatedTypes = codegen.generateTypes();
+    await testEntity(generatedTypes, {
+      name: 'Task',
+      members: [],
+      methods: [
+        {
+          name: 'constructor',
+          params: [new Param('id', new NamedType('Int8'))],
+          returnType: undefined,
+          body: "\n      super()\n      this.set('id', Value.fromI64(id))\n      ",
+        },
+        {
+          name: 'save',
+          params: [],
+          returnType: new NamedType('void'),
+          body:
+            '\n' +
+            "        let id = this.get('id')\n" +
+            '        assert(id != null,\n' +
+            "               'Cannot save Task entity without an ID')\n" +
+            '        if (id) {\n' +
+            '          assert(id.kind == ValueKind.INT8,\n' +
+            "                 `Entities of type Task must have an ID of type Int8 but the id '${id.displayData()}' is of type ${id.displayKind()}`)\n" +
+            "          store.set('Task', id.toI64().toString(), this)\n" +
+            '        }',
+        },
+        {
+          name: 'loadInBlock',
+          static: true,
+          params: [new Param('id', new NamedType('Int8'))],
+          returnType: new NullableType(new NamedType('Task')),
+          body:
+            '\n' +
+            "        return changetype<Task | null>(store.get_in_block('Task', id.toString()))\n" +
+            '        ',
+        },
+        {
+          name: 'load',
+          static: true,
+          params: [new Param('id', new NamedType('Int8'))],
+          returnType: new NullableType(new NamedType('Task')),
+          body:
+            '\n' +
+            "        return changetype<Task | null>(store.get('Task', id.toString()))\n" +
+            '        ',
+        },
+        {
+          name: 'get id',
+          params: [],
+          returnType: new NamedType('i64'),
+          body: `let value = this.get("id")
+            if (!value || value.kind == ValueKind.NULL) {
+               return 0;
+             } else {
+               return value.toI64()
+             }`,
+        },
+        {
+          name: 'set id',
+          params: [new Param('value', new NamedType('i64'))],
+          returnType: undefined,
+          body: "\n      this.set('id', Value.fromI64(value))\n    ",
+        },
+        {
+          name: 'get employee',
+          params: [],
+          returnType: new NamedType('i64'),
+          body: `let value = this.get('employee')
+            if (!value || value.kind == ValueKind.NULL) {
+              return 0;
+            } else {
+              return value.toI64()
+            }`,
+        },
+        {
+          name: 'set employee',
+          params: [new Param('value', new NamedType('i64'))],
+          returnType: undefined,
+          body: "\n      this.set('employee', Value.fromI64(value))\n    ",
+        },
+        {
+          name: 'get worker',
+          params: [],
+          returnType: new NamedType('i64'),
+          body: `let value = this.get('worker')
+          if (!value || value.kind == ValueKind.NULL) {
+            return 0;
+          } else {
+            return value.toI64()
+          }`,
+        },
+        {
+          name: 'set worker',
+          params: [new Param('value', new NamedType('i64'))],
+          returnType: undefined,
+          body: "\n      this.set('worker', Value.fromI64(value))\n    ",
+        },
+        {
+          name: 'get workers',
+          params: [],
+          returnType: new NamedType('WorkerLoader'),
+          body: "\n      return new WorkerLoader('Task', this.get('id')!.toString(), 'workers')\n    ",
+        },
+      ],
+    });
+  });
+
   test('get related method for WithBytes entity', async () => {
     const codegen = createSchemaCodeGen(`
       type WithBytes @entity {
diff --git a/packages/cli/src/command-helpers/subgraph.test.ts b/packages/cli/src/command-helpers/subgraph.test.ts
new file mode 100644
index 00000000..b3ac994e
--- /dev/null
+++ b/packages/cli/src/command-helpers/subgraph.test.ts
@@ -0,0 +1,50 @@
+import { describe, expect, it } from 'vitest';
+import { formatContractName, formatSubgraphName, getSubgraphBasename } from './subgraph';
+
+describe('getSubgraphBasename', () => {
+  it('returns the last segment of a subgraph name', () => {
+    expect(getSubgraphBasename('user/my-subgraph')).toBe('my-subgraph');
+    expect(getSubgraphBasename('org/project')).toBe('project');
+  });
+
+  it('returns the full name if no slash is present', () => {
+    expect(getSubgraphBasename('single-name')).toBe('single-name');
+  });
+});
+
+describe('formatSubgraphName', () => {
+  it('converts to lowercase', () => {
+    expect(formatSubgraphName('MySubGraph')).toBe('mysubgraph');
+  });
+
+  it('replaces spaces with hyphens', () => {
+    expect(formatSubgraphName('my subgraph name')).toBe('my-subgraph-name');
+    expect(formatSubgraphName('multiple   spaces')).toBe('multiple-spaces');
+  });
+
+  it('removes special characters', () => {
+    expect(formatSubgraphName('my$special@subgraph!')).toBe('myspecialsubgraph');
+  });
+
+  it('keeps alphanumeric characters, hyphens and underscores', () => {
+    expect(formatSubgraphName('my-subgraph_123')).toBe('my-subgraph_123');
+  });
+});
+
+describe('formatContractName', () => {
+  it('replaces spaces and dots with underscores', () => {
+    expect(formatContractName('My Contract')).toBe('My_Contract');
+    expect(formatContractName('contract.name')).toBe('contract_name');
+    expect(formatContractName('multiple...dots')).toBe('multiple_dots');
+  });
+
+  it('removes special characters but keeps alphanumeric, hyphens and underscores', () => {
+    expect(formatContractName('Contract$$$Name')).toBe('ContractName');
+    expect(formatContractName('My-Contract_123')).toBe('My-Contract_123');
+    expect(formatContractName('My Contract $$$$')).toBe('My_Contract_');
+  });
+
+  it('preserves case', () => {
+    expect(formatContractName('MyContractName')).toBe('MyContractName');
+  });
+});
diff --git a/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap
index f9e5d47a..53189f25 100644
--- a/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap
+++ b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap
@@ -1,7 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`Cosmos subgraph scaffolding > Manifest 1`] = `
-"specVersion: 1.0.0
+"specVersion: 1.2.0
 indexerHints:
   prune: auto
 schema:
diff --git a/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap
index b76a3860..e0264847 100644
--- a/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap
+++ b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap
@@ -1,7 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`Ethereum subgraph scaffolding > Manifest 1`] = `
-"specVersion: 1.0.0
+"specVersion: 1.2.0
 indexerHints:
   prune: auto
 schema:
@@ -16,7 +16,7 @@ dataSources:
       startBlock: 12345
     mapping:
       kind: ethereum/events
-      apiVersion: 0.0.7
+      apiVersion: 0.0.9
       language: wasm/assemblyscript
       entities:
         - ExampleEvent
@@ -30,7 +30,7 @@ dataSources:
           handler: handleExampleEvent
         - event: ExampleEvent(bytes32)
           handler: handleExampleEvent1
-        - event: TupleArrayEvent((uint256,address)[],address[])
+        - event: TupleArrayEvent((uint256,address)[],address[],address[10])
           handler: handleTupleArrayEvent
       file: ./src/contract.ts
 "
@@ -153,6 +153,7 @@ export function handleTupleArrayEvent(event: TupleArrayEventEvent): void {
   )
   entity.tupleArray = changetype<Bytes[]>(event.params.tupleArray)
   entity.addressArray = changetype<Bytes[]>(event.params.addressArray)
+  entity.addressSizedArray = changetype<Bytes[]>(event.params.addressSizedArray)
 
   entity.blockNumber = event.block.number
   entity.blockTimestamp = event.block.timestamp
@@ -266,6 +267,7 @@ type TupleArrayEvent @entity(immutable: true) {
   id: Bytes!
   tupleArray: [Bytes!]! # tuple[]
   addressArray: [Bytes!]! # address[]
+  addressSizedArray: [Bytes!]! # address[10]
   blockNumber: BigInt!
   blockTimestamp: BigInt!
   transactionHash: Bytes!
@@ -409,7 +411,8 @@ export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
 
 export function createTupleArrayEventEvent(
   tupleArray: Array<ethereum.Tuple>,
-  addressArray: Array<Address>
+  addressArray: Array<Address>,
+  addressSizedArray: Array<Address>
 ): TupleArrayEvent {
   let tupleArrayEventEvent = changetype<TupleArrayEvent>(newMockEvent())
 
@@ -427,6 +430,12 @@ export function createTupleArrayEventEvent(
       ethereum.Value.fromAddressArray(addressArray)
     )
   )
+  tupleArrayEventEvent.parameters.push(
+    new ethereum.EventParam(
+      "addressSizedArray",
+      ethereum.Value.fromAddressArray(addressSizedArray)
+    )
+  )
 
   return tupleArrayEventEvent
 }
@@ -569,7 +578,8 @@ export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
 
 export function createTupleArrayEventEvent(
   tupleArray: Array<ethereum.Tuple>,
-  addressArray: Array<Address>
+  addressArray: Array<Address>,
+  addressSizedArray: Array<Address>
 ): TupleArrayEvent {
   let tupleArrayEventEvent = changetype<TupleArrayEvent>(newMockEvent())
 
@@ -587,6 +597,12 @@ export function createTupleArrayEventEvent(
       ethereum.Value.fromAddressArray(addressArray)
     )
   )
+  tupleArrayEventEvent.parameters.push(
+    new ethereum.EventParam(
+      "addressSizedArray",
+      ethereum.Value.fromAddressArray(addressSizedArray)
+    )
+  )
 
   return tupleArrayEventEvent
 }
diff --git a/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap
index d5fb1f80..60867ffa 100644
--- a/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap
+++ b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap
@@ -1,7 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`NEAR subgraph scaffolding > Manifest 1`] = `
-"specVersion: 1.0.0
+"specVersion: 1.2.0
 indexerHints:
   prune: auto
 schema:
diff --git a/packages/cli/src/scaffold/ethereum.test.ts b/packages/cli/src/scaffold/ethereum.test.ts
index da4d7e99..9652039c 100644
--- a/packages/cli/src/scaffold/ethereum.test.ts
+++ b/packages/cli/src/scaffold/ethereum.test.ts
@@ -69,6 +69,7 @@ const TEST_TUPLE_ARRAY_EVENT = {
       ],
     },
     { name: 'addressArray', type: 'address[]' },
+    { name: 'addressSizedArray', type: 'address[10]' },
   ],
 };
 
diff --git a/packages/cli/tests/cli/add/expected/subgraph.yaml b/packages/cli/tests/cli/add/expected/subgraph.yaml
index 5756ec28..a0782a9c 100644
--- a/packages/cli/tests/cli/add/expected/subgraph.yaml
+++ b/packages/cli/tests/cli/add/expected/subgraph.yaml
@@ -35,7 +35,7 @@ dataSources:
       startBlock: 6175244
     mapping:
       kind: ethereum/events
-      apiVersion: 0.0.7
+      apiVersion: 0.0.9
       language: wasm/assemblyscript
       entities:
         - GravatarNewGravatar