defactor.ai

Agent Quick Start

This guide is designed for AI agents and autonomous systems. It provides everything needed to programmatically interact with the Defactor protocol: authentication, asset tokenization, lending, governance, and error handling.

Prerequisites

Node.js 18+ runtime environment
Ethereum wallet with private key (for SelfProvider mode)
RPC endpoint for target chain (Alchemy, Infura, or public)
FACTR tokens for staking/governance (optional)
Lending tokens (USDC, USDT, etc.) for pool interactions

Agent Manifest (JSON-LD)

Machine-readable capability manifest. AI agents can parse this to understand what operations are available and how to access them.

defactor-agent-manifest.jsonjson
1{
2 "@context": "https://schema.org",
3 "@type": "APIReference",
4 "name": "Defactor Protocol Agent Interface",
5 "version": "2.0.0",
6 "description": "Machine-readable interface for AI agents to tokenize, lend, govern, and manage real-world assets on-chain.",
7 "provider": {
8 "@type": "Organization",
9 "name": "Defactor",
10 "url": "https://defactor.com"
11 },
12 "capabilities": [
13 {
14 "name": "Asset Tokenization",
15 "description": "Create ERC-20 and ERC-3643 tokens backed by real-world assets",
16 "api": "GraphQL + REST",
17 "endpoint": "https://api.defactor.com/graphql",
18 "documentation": "https://defactor.ai/assets"
19 },
20 {
21 "name": "Lending Pools",
22 "description": "Create and interact with RWA-collateralized lending pools",
23 "api": "Smart Contract (SDK)",
24 "contract": "ERC20CollateralPool",
25 "documentation": "https://defactor.ai/pools"
26 },
27 {
28 "name": "Governance & Staking",
29 "description": "Stake FACTR tokens and participate in protocol governance",
30 "api": "Smart Contract (SDK)",
31 "contract": "Engage",
32 "documentation": "https://defactor.ai/engage"
33 },
34 {
35 "name": "Counterparty Pools",
36 "description": "Bilateral lending agreements between specific parties",
37 "api": "Smart Contract (SDK)",
38 "contract": "CounterpartyPool",
39 "documentation": "https://defactor.ai/pools"
40 }
41 ],
42 "authentication": {
43 "type": "Wallet Signature (EIP-191)",
44 "flow": ["generateNonce", "signMessage", "verifySignature"],
45 "result": "JWT Bearer Token"
46 },
47 "supportedChains": [
48 { "name": "Ethereum", "chainId": 1 },
49 { "name": "Polygon", "chainId": 137 },
50 { "name": "Base", "chainId": 8453 },
51 { "name": "BSC", "chainId": 56 }
52 ],
53 "sdk": {
54 "package": "@defactor/defactor-sdk",
55 "version": "7.4.0",
56 "runtime": "Node.js 18+",
57 "language": "TypeScript",
58 "repository": "https://github.com/defactor-com/sdk"
59 }
60}

Agent Decision Tree

Use this decision tree to determine which API or contract to call based on the desired operation.

Decision Treetext
// Agent Decision Tree for Defactor Operations
//
// START
// ├── Need to tokenize a new asset?
// │   ├── Yes → Use Assets API (REST or GraphQL)
// │   │   ├── ERC-20 standard → Simple fungible token
// │   │   └── ERC-3643 standard → Compliant security token (needs KYC)
// │   └── No → Continue
// │
// ├── Need to interact with lending?
// │   ├── As Lender → pools.lend(poolId, amount)
// │   │   └── Requires: ERC-20 approval first
// │   ├── As Borrower → pools.borrow(poolId, amount)
// │   │   └── Requires: Sufficient collateral deposited
// │   └── As Liquidator → pools.liquidatePool(poolId)
// │       └── Requires: Pool health factor < 100%
// │
// ├── Need to participate in governance?
// │   ├── Stake FACTR → engage.stake(planId, amount)
// │   ├── Vote → engage.vote(proposalId, support)
// │   └── Claim rewards → engage.claimRewards(planId)
// │
// └── Need bilateral lending?
//     └── Use Counterparty Pools
//         ├── Create → createCounterpartyPool(params)
//         └── Interact → same as standard pools

Safety Guidelines for Agents

Always check balances before transactions

Query token balances and allowances before attempting transfers, lending, or staking to avoid reverted transactions and wasted gas.

Verify pool status before interaction

Check pool deadline, status (ACTIVE/CLOSED/LIQUIDATED), and capacity (current vs hard cap) before lending or borrowing.

Handle gas estimation failures gracefully

If gas estimation fails, the transaction will likely revert. Catch the error and diagnose the root cause before retrying.

Use nonce management for concurrent transactions

When sending multiple transactions in parallel, manage nonces manually to prevent nonce conflicts.

Monitor for chain reorganizations

Wait for sufficient block confirmations (12+ on Ethereum, 128+ on Polygon) before considering transactions final.

Complete Agent Implementation

A full working example of an AI agent that authenticates, tokenizes an asset, lends to a pool, stakes FACTR, and votes on governance proposals.

defactor-agent.tstypescript
1// ============================================
2// DEFACTOR AI AGENT — Complete Implementation
3// ============================================
4// This agent tokenizes an asset, creates a lending pool,
5// stakes FACTR, and participates in governance.
6
7import { ethers } from 'ethers'
8import {
9 ERC20CollateralPool,
10 Engage,
11 SelfProvider
12} from '@defactor/defactor-sdk'
13
14// ---- CONFIGURATION ----
15const CONFIG = {
16 rpc: 'https://polygon-rpc.com',
17 privateKey: process.env.AGENT_PRIVATE_KEY!,
18 contracts: {
19 pool: '0x...ERC20CollateralPool',
20 engage: '0x...Engage',
21 factr: '0x...FACTR',
22 usdc: '0x...USDC'
23 },
24 api: 'https://api.defactor.com'
25}
26
27// ---- STEP 1: AUTHENTICATE ----
28async function authenticate() {
29 const wallet = new ethers.Wallet(CONFIG.privateKey)
30
31 // Get nonce
32 const nonceRes = await fetch(`${CONFIG.api}/v1/generate-nonce`)
33 const { res: nonce } = await nonceRes.json()
34
35 // Sign nonce
36 const message = `Authenticate: ${nonce}`
37 const signature = await wallet.signMessage(message)
38
39 // Verify and get JWT
40 const authRes = await fetch(`${CONFIG.api}/v1/verify-signature`, {
41 method: 'POST',
42 headers: { 'Content-Type': 'application/json' },
43 body: JSON.stringify({
44 address: wallet.address,
45 chainId: 137,
46 message,
47 signature
48 })
49 })
50
51 const { res: { token } } = await authRes.json()
52 return { token, wallet }
53}
54
55// ---- STEP 2: TOKENIZE AN ASSET ----
56async function tokenizeAsset(token: string) {
57 const res = await fetch(`${CONFIG.api}/v1/assets`, {
58 method: 'POST',
59 headers: {
60 'Content-Type': 'application/json',
61 'Authorization': `Bearer ${token}`
62 },
63 body: JSON.stringify({
64 name: 'Commercial Real Estate Fund A',
65 symbol: 'CREFA',
66 totalSupply: ethers.parseEther('1000000').toString(),
67 standard: 'ERC-20',
68 chainId: 137,
69 metadata: {
70 assetType: 'Real Estate',
71 jurisdiction: 'US',
72 valuationDate: '2026-03-01',
73 totalValue: '10000000' // $10M USD
74 }
75 })
76 })
77 return await res.json()
78}
79
80// ---- STEP 3: INTERACT WITH POOLS ----
81async function managePools() {
82 const poolProvider = new SelfProvider.SelfProvider<ERC20CollateralPool>(
83 ERC20CollateralPool,
84 CONFIG.contracts.pool,
85 CONFIG.rpc,
86 CONFIG.privateKey
87 )
88
89 // Discover pools
90 const total = await poolProvider.contract.getTotalPools()
91 const pools = await poolProvider.contract.getPools(0n, total)
92
93 // Find best lending opportunity
94 const activePools = pools.filter(p => p.status === 'ACTIVE')
95 const bestPool = activePools.reduce((best, pool, idx) => {
96 const rate = Number(pool.interestRate)
97 return rate > best.rate ? { idx, rate } : best
98 }, { idx: 0, rate: 0 })
99
100 // Approve USDC spending
101 const usdc = new ethers.Contract(
102 CONFIG.contracts.usdc,
103 ['function approve(address,uint256) returns (bool)'],
104 new ethers.Wallet(CONFIG.privateKey, new ethers.JsonRpcProvider(CONFIG.rpc))
105 )
106 const lendAmount = ethers.parseUnits('10000', 6) // 10,000 USDC
107 await usdc.approve(CONFIG.contracts.pool, lendAmount)
108
109 // Lend to pool
110 await poolProvider.contract.lend(BigInt(bestPool.idx), lendAmount)
111
112 return { poolId: bestPool.idx, amount: lendAmount }
113}
114
115// ---- STEP 4: STAKE & GOVERN ----
116async function stakeAndGovern() {
117 const engageProvider = new SelfProvider.SelfProvider<Engage>(
118 Engage,
119 CONFIG.contracts.engage,
120 CONFIG.rpc,
121 CONFIG.privateKey
122 )
123
124 // Stake FACTR
125 const plans = await engageProvider.contract.getStakingPlans()
126 const bestPlan = plans[0] // Select optimal plan
127 await engageProvider.contract.stake(bestPlan.planId, ethers.parseEther('1000'))
128
129 // Vote on active proposals
130 const proposals = await engageProvider.contract.getProposals(0n, 10n)
131 for (const p of proposals) {
132 if (p.status === 'ACTIVE') {
133 await engageProvider.contract.vote(p.proposalId, true)
134 }
135 }
136}
137
138// ---- MAIN EXECUTION ----
139async function main() {
140 console.log('[Agent] Starting Defactor operations...')
141
142 const { token } = await authenticate()
143 console.log('[Agent] Authenticated successfully')
144
145 const asset = await tokenizeAsset(token)
146 console.log('[Agent] Asset tokenized:', asset)
147
148 const pool = await managePools()
149 console.log('[Agent] Lent to pool:', pool)
150
151 await stakeAndGovern()
152 console.log('[Agent] Staked and voted')
153
154 console.log('[Agent] All operations complete')
155}
156
157main().catch(console.error)

Explore Further