Skip to Content

Advanced SDK Usage

🚧

Coming Soon — The ChainSocial SDK is not yet published. This documentation describes the planned API. Use the REST API for current integrations.

Delegation, meta-transactions, and advanced patterns.

Delegation

Delegation lets users grant specific permissions to other addresses. This enables:

  • Session Keys — Better UX with fewer wallet popups
  • Gasless Transactions — Relayers can act on behalf of users
  • Bots & Assistants — Automated actions with limited scope

Permission Types

PermissionValueDescription
POST0Create posts, replies, quotes
UPDATE_PROFILE1Modify profile fields
SEND_DMS2Send direct messages
FOLLOW3Follow/unfollow users

Creating a Delegation

import { DelegationPermission } from '@chainsocial/client' // Grant posting permission to another address for 7 days const sevenDays = Math.floor(Date.now() / 1000) + (7 * 24 * 60 * 60) await client.delegation.createDelegation( delegateAddress, DelegationPermission.POST, sevenDays // validUntil timestamp )

Revoking a Delegation

await client.delegation.revokeDelegation( delegateAddress, DelegationPermission.POST )

Checking Authorization

const isAuthorized = await client.delegation.isDelegateAuthorized( delegatorAddress, // Original user delegateAddress, // Acting address DelegationPermission.POST )

Using Delegated Permissions

Once delegated, the delegate wallet can use OnBehalfOf methods:

// Delegate creates post as the delegator await client.post.createInlinePostOnBehalfOf( delegatorAddress, 'Posted via delegation!', PostVisibility.PUBLIC )

Delegations expire automatically at the validUntil timestamp. Maximum delegation duration is 365 days.

Meta-Transactions (Signed Operations)

Meta-transactions let users sign operations off-chain, then have a relayer submit them. This enables gasless UX.

How It Works

  1. User signs an EIP-712 typed message
  2. Relayer receives the signature
  3. Relayer submits the transaction and pays gas
  4. User’s action is recorded on-chain

Signing an Operation

import { SignedOperations } from '@chainsocial/client' const signedOps = new SignedOperations({ worldAddress, chainId: 8453, walletClient }) // Sign a post creation const signature = await signedOps.signCreatePost({ contentId: '0x...', visibility: PostVisibility.PUBLIC, nonce: currentNonce, deadline: Math.floor(Date.now() / 1000) + 3600 // 1 hour expiry }) // Send signature to relayer await fetch('/api/relay', { method: 'POST', body: JSON.stringify({ signature, params: { contentId, visibility } }) })

Supported Signed Operations

CategoryOperations
ContentCreate/Edit/Delete posts, replies, quotes
SocialFollow/unfollow, block/unblock
ReactionsAdd/remove reactions
DMsSend messages
ProfileUpdate profile fields
DelegationCreate/revoke delegations

Relayer System

ChainSocial includes built-in relayer support with fee management.

Relayer Vault

Users can deposit ETH into a relayer vault for gasless transactions:

// Deposit ETH for gas coverage await client.relayerVault.deposit({ value: parseEther('0.1') }) // Check balance const balance = await client.relayerVault.getBalance(userAddress) // Withdraw await client.relayerVault.withdraw(parseEther('0.05'))

Relayer Fee Configuration

Relayers charge fees based on gas used, with configurable bounds:

const feeConfig = await client.relayerFee.getFeeConfig() console.log('Min fee:', feeConfig.minFee) console.log('Max fee:', feeConfig.maxFee) console.log('Fixed gas price:', feeConfig.fixedGasPrice)

Signed Operations with Max Fee

Users can cap the fee they’re willing to pay:

const signature = await signedOps.signCreatePost({ contentId: '0x...', visibility: PostVisibility.PUBLIC, nonce: currentNonce, deadline: deadline, maxFee: parseEther('0.001') // Won't pay more than 0.001 ETH })

Content System

The content system handles storage of text and media.

Storage Types

import { ContentStorageType } from '@chainsocial/client' // Inline (on-chain, up to 4KB) const id1 = await client.content.createInlineContent('Hello world') // IPFS reference const id2 = await client.content.createIpfsContent( 'bafkrei...', // CID 'image/png', 12345 // size in bytes ) // URL reference const id3 = await client.content.createUrlContent( 'https://example.com/post.json', 'application/json' )

Reading Content

const contentData = await client.content.getContent(contentId) console.log('Storage type:', contentData.storageType) console.log('MIME type:', contentData.mimeType) console.log('Size:', contentData.size) console.log('Data:', contentData.data) // For inline content

Username System

Usernames can have fees and expiration (configurable by namespace owner).

Claiming a Username

import { stringToHex, padHex } from 'viem' const username = padHex(stringToHex('alice'), { size: 32 }) const fee = await client.username.getFee(username) await client.username.claimUsername(username, { value: fee })

Renewing a Username

const renewalFee = await client.username.getRenewalFee(username) await client.username.renewUsername(username, { value: renewalFee })

Releasing a Username

await client.username.releaseUsername(username)

Plugin System

Users can install and manage plugins:

// Install a plugin await client.pluginInstall.installPlugin(pluginId) // Grant consent for plugin to act await client.pluginInstall.grantConsent(pluginId) // Uninstall await client.pluginInstall.uninstallPlugin(pluginId)

Moderation System

Reporting Content

await client.moderation.reportPost(postId, 'spam', 'This is spam content') await client.moderation.reportUser(userAddress, 'harassment')

Hiding Content (Personal)

// Hide a post from your feed (only affects you) await client.moderation.hideContent(postId) // Unhide await client.moderation.unhideContent(postId)

Best Practices

Transaction Batching

Combine multiple operations when possible:

// Instead of 3 transactions await client.follow.follow(user1) await client.follow.follow(user2) await client.follow.follow(user3) // Use 1 batch transaction await client.follow.followBatch([user1, user2, user3])

Error Handling

try { await client.post.createInlinePost('Hello!') } catch (error) { // Contract reverts include reason strings if (error.message.includes('ProfileNotFound')) { // User needs a profile } else if (error.message.includes('InsufficientFee')) { // Need to send more ETH } else if (error.message.includes('ContentTooLong')) { // Inline content exceeds 4KB } throw error }

Gas Optimization

  • Use inline content for small text (under 1KB)
  • Use IPFS for larger content (saves on-chain storage)
  • Batch operations when possible
  • Use delegation for apps with high transaction volume

Next Steps