Skip to main content

Writes

Understanding Mutations vs Smart Contract Operations​

The Intuition GraphQL API provides mutations for off-chain operations like uploading metadata to IPFS. For on-chain operations like creating atoms, triples, and positions, you must use the Intuition SDK or interact directly with the smart contracts.

GraphQL vs Smart Contracts

GraphQL mutations handle:

  • Uploading metadata to IPFS (pinThing, pinPerson, pinOrganization)

Smart contract operations handle:

  • Creating atoms
  • Creating triples
  • Taking positions (depositing/redeeming)
  • All on-chain state changes

Use the SDK for smart contract interactions.

Available Mutations​

IPFS & Metadata Mutations​

MutationDescriptionDocumentation
pinThingPin Thing metadata to IPFSPin Thing
pinPersonPin Person metadata to IPFSPin Person
pinOrganizationPin Organization metadata to IPFSPin Organization
uploadImageUpload base64 image to IPFSUpload Image
uploadImageFromUrlUpload image from URL to IPFSUpload from URL
uploadJsonToIpfsUpload JSON metadata to IPFSUpload JSON
Read-Only Operations

Chart and PnL operations are queries, not mutations. See:

Pin Mutations​

pinThing Mutation​

Pin a Thing entity to IPFS:

mutation PinThing($thing: PinThingInput!) {
pinThing(thing: $thing) {
hash
name
size
}
}

Variables:

{
"thing": {
"name": "Ethereum",
"description": "A decentralized blockchain platform",
"image": "ipfs://QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy",
"url": "https://ethereum.org"
}
}

pinPerson Mutation​

Pin a Person entity to IPFS:

mutation PinPerson($person: PinPersonInput!) {
pinPerson(person: $person) {
hash
name
size
}
}

Variables:

{
"person": {
"name": "Vitalik Buterin",
"description": "Co-founder of Ethereum",
"email": "vitalik@ethereum.org",
"identifier": "vitalik.eth",
"image": "ipfs://Qm...",
"url": "https://vitalik.ca"
}
}

pinOrganization Mutation​

Pin an Organization entity to IPFS:

mutation PinOrganization($organization: PinOrganizationInput!) {
pinOrganization(organization: $organization) {
hash
name
size
}
}

Variables:

{
"organization": {
"name": "Ethereum Foundation",
"description": "Non-profit supporting Ethereum",
"email": "info@ethereum.org",
"image": "ipfs://Qm...",
"url": "https://ethereum.foundation"
}
}

Image Upload Mutations​

uploadImage​

Upload a base64-encoded image:

mutation UploadImage($image: UploadImageInput!) {
uploadImage(image: $image) {
images {
url
original_url
safe
score
model
created_at
}
}
}

uploadImageFromUrl​

Upload an image from a URL:

mutation UploadImageFromUrl($image: UploadImageFromUrlInput!) {
uploadImageFromUrl(image: $image) {
images {
url
original_url
safe
score
}
}
}

uploadJsonToIpfs​

Upload JSON metadata:

mutation UploadJsonToIpfs($json: jsonb!) {
uploadJsonToIpfs(json: $json) {
hash
name
size
}
}

Complete Workflow Example​

Here's how to prepare metadata for atom creation:

import { GraphQLClient } from 'graphql-request'
import { API_URL_PROD } from '@0xintuition/graphql'
import { createMultivaultClient } from '@0xintuition/sdk'

const graphqlClient = new GraphQLClient(API_URL_PROD)

// Step 1: Upload image to IPFS (via GraphQL)
const imageResult = await graphqlClient.request(`
mutation UploadImageFromUrl($image: UploadImageFromUrlInput!) {
uploadImageFromUrl(image: $image) {
images {
url
}
}
}
`, { image: { url: 'https://example.com/logo.png' } })

// Step 2: Upload metadata to IPFS (via GraphQL)
const metadataResult = await graphqlClient.request(`
mutation PinThing($thing: PinThingInput!) {
pinThing(thing: $thing) {
hash
}
}
`, {
thing: {
name: 'My Project',
description: 'Description of my project',
image: imageResult.uploadImageFromUrl.images[0].url,
url: 'https://example.com'
}
})

// Step 3: Create atom on-chain (via SDK)
const multivault = createMultivaultClient(walletClient)
const atomId = await multivault.createAtom({
uri: `ipfs://${metadataResult.pinThing.hash}`
})

Best Practices​

1. Complete Metadata​

Provide comprehensive metadata for better discoverability:

const thing = {
name: 'Project Name', // Required
description: 'Full description', // Recommended
image: 'ipfs://...', // Recommended
url: 'https://...' // Optional
}

2. Use IPFS URLs​

Always reference images using IPFS URLs for permanence:

// Good - permanent
image: 'ipfs://QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy'

// Avoid - may change
image: 'https://example.com/image.png'

3. Error Handling​

try {
const result = await graphqlClient.request(UPLOAD_IMAGE, { image: input })
console.log('Uploaded:', result.uploadImage.images[0].url)
} catch (error) {
if (error.message.includes('File too large')) {
console.error('Image exceeds size limit')
} else if (error.message.includes('Invalid')) {
console.error('Invalid image format')
}
}

4. Size Limits​

Upload TypeMaximum Size
Image (base64)5 MB
Image from URL10 MB
JSON1 MB

TypeScript Integration​

Use the @0xintuition/graphql package for type-safe mutations:

import {
usePinThingMutation,
useUploadImageFromUrlMutation
} from '@0xintuition/graphql'

function CreateAtomForm() {
const [pinThing] = usePinThingMutation()
const [uploadImage] = useUploadImageFromUrlMutation()

const handleSubmit = async (data: FormData) => {
// Upload image first
const imageResult = await uploadImage({
variables: { image: { url: data.imageUrl } }
})

// Then pin metadata
const thingResult = await pinThing({
variables: {
thing: {
name: data.name,
description: data.description,
image: imageResult.data.uploadImageFromUrl.images[0].url,
url: data.url
}
}
})

// Use the IPFS hash for atom creation
const ipfsUri = `ipfs://${thingResult.data.pinThing.hash}`
// ... create atom via SDK
}

return <form onSubmit={handleSubmit}>...</form>
}