Documentation Index
Fetch the complete documentation index at: https://docs.incentiv.io/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Incentiv SDK (@incentiv/dapp-sdk) provides a seamless way to connect your decentralized application (dApp) to the Incentiv blockchain network. It includes:
- IncentivResolver: For wallet connection and account management
- IncentivSigner: For signing transactions and interacting with smart contracts
The SDK supports Account Abstraction (AA) wallets, enabling gasless transactions and improved user experience.
Prerequisites
Before you begin, ensure you have:
- Node.js (v16 or higher)
- npm or yarn package manager
- Incentiv Wallet Extension installed in your browser
- Basic knowledge of:
- React/JavaScript
- Ethereum/Web3 concepts
- Smart contracts
Installation
Step 1: Install the SDK
Install the Incentiv DApp SDK using npm:
npm install @incentiv/dapp-sdk ethers@5.7.2
Or using yarn:
yarn add @incentiv/dapp-sdk ethers@5.7.2
Step 2: Install Additional Dependencies
The SDK requires buffer for Node.js compatibility in browser environments:
Project Setup
Vite Configuration
If you’re using Vite, configure it to support the SDK:
vite.config.js:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
define: {
global: 'globalThis',
},
resolve: {
alias: {
buffer: 'buffer',
},
},
optimizeDeps: {
include: ['buffer'],
},
});
Environment Variables
Create a configuration file for your environment settings:
src/config.js:
const Config = {
SC: {
address: "0xC3A195E....." // Your contract address
},
Environments: {
Mainnet: {
Portal: "https://portal.incentiv.io",
RPC: "https://rpc.incentiv.io"
}
},
API: {
baseURL: import.meta.env.VITE_API_URL || "https://your-api.com/api"
}
};
export default Config;
Environment Variables Template
Create a .env file (or use environment variables):
VITE_API_URL=https://your-api.com/api
VITE_ENVIRONMENT=mainnet
VITE_CONTRACT_ADDRESS=0xC3A195E.....
Connecting to Wallet
Step 1: Import Required Modules
import { IncentivResolver, IncentivSigner } from "@incentiv/dapp-sdk";
import { ethers } from "ethers";
import Config from "./config";
Step 2: Connect to Wallet
The IncentivResolver is used to connect to the user’s wallet and get their account address:
const handleConnect = async () => {
try {
// Check if IncentivResolver is available
if (typeof IncentivResolver === "undefined") {
throw new Error(
"Incentiv wallet extension not found. Please install the Incentiv wallet extension."
);
}
// Get the user's wallet address
const address = await IncentivResolver.getAccountAddress(
Config.Environments.Mainnet.Portal
);
// Validate the address
if (!address || address === "null" || address === null) {
throw new Error(
"No wallet address received. Please make sure your wallet is connected."
);
}
console.log("Connected address:", address);
setAddress(address);
// Initialize contract connection (see next section)
await fetchContractData(address);
} catch (err) {
console.error("Connection error:", err);
// Handle error (show toast, etc.)
}
};
Complete Wallet Connection Example
import { useState } from "react";
import { IncentivResolver } from "@incentiv/dapp-sdk";
import Config from "./config";
function WalletConnection() {
const [address, setAddress] = useState("");
const [isConnecting, setIsConnecting] = useState(false);
const [error, setError] = useState("");
const handleConnect = async () => {
setIsConnecting(true);
setError("");
try {
// Check if wallet extension is available
if (typeof IncentivResolver === "undefined") {
throw new Error(
"Incentiv wallet extension not found. Please install the Incentiv wallet extension."
);
}
// Connect to wallet
const userAddress = await IncentivResolver.getAccountAddress(
Config.Environments.Mainnet.Portal
);
// Validate address
if (!userAddress || userAddress === "null" || userAddress === null) {
throw new Error(
"No wallet address received. Please make sure your wallet is connected and you've approved the connection."
);
}
setAddress(userAddress);
console.log("Wallet connected:", userAddress);
} catch (err) {
console.error("Connection error:", err);
setError(err.message || "Failed to connect wallet");
} finally {
setIsConnecting(false);
}
};
return (
<div>
{!address ? (
<button onClick={handleConnect} disabled={isConnecting}>
{isConnecting ? "Connecting..." : "Connect Wallet"}
</button>
) : (
<div>
<p>Connected: {address}</p>
</div>
)}
{error && <p style={{ color: "red" }}>{error}</p>}
</div>
);
}
Initializing the Signer
After connecting to the wallet, you need to initialize the IncentivSigner to interact with smart contracts. The signer uses Account Abstraction (AA) for gasless transactions.
Step 1: Create Provider
import { ethers } from "ethers";
const provider = new ethers.providers.JsonRpcProvider(
Config.Environments.Mainnet.RPC
);
Step 2: Initialize IncentivSigner
import { IncentivSigner } from "@incentiv/dapp-sdk";
const signer = new IncentivSigner({
address: userAddress, // From wallet connection
provider: provider,
environment: Config.Environments.Mainnet.Portal,
entryPoint: "[EntryPoint contract address]", // EntryPoint contract address
});
Step 3: Create Contract Instance
import ABI from "./YourContractABI.json";
const contractAddress = Config.GamePot.address;
const contract = new ethers.Contract(contractAddress, ABI, signer);
Complete Signer Initialization Example
import { useRef, useState } from "react";
import { IncentivResolver, IncentivSigner } from "@incentiv/dapp-sdk";
import { ethers } from "ethers";
import ABI from "./YourContractABI.json";
import Config from "./config";
function App() {
const [address, setAddress] = useState("");
const [contract, setContract] = useState(null);
const signerRef = useRef(null);
// Fetch contract data and initialize signer
async function fetchContractData(userAddress) {
try {
// Create provider
const provider = new ethers.providers.JsonRpcProvider(
Config.Environments.Mainnet.RPC
);
// Initialize IncentivSigner
const signer = new IncentivSigner({
address: userAddress,
provider: provider,
environment: Config.Environments.Mainnet.Portal,
entryPoint: "[EntryPoint contract address]",
});
// Store signer reference
signerRef.current = signer;
// Create contract instance
const contractInstance = new ethers.Contract(
Config.SC.address,
ABI,
signer
);
setContract(contractInstance);
console.log("Contract initialized:", contractInstance);
} catch (err) {
console.error("Failed to initialize contract:", err);
setContract(null);
signerRef.current = null;
}
}
// Connect wallet and initialize
const handleConnect = async () => {
try {
const userAddress = await IncentivResolver.getAccountAddress(
Config.Environments.Mainnet.Portal
);
setAddress(userAddress);
await fetchContractData(userAddress);
} catch (err) {
console.error("Connection error:", err);
}
};
return (
<div>
{!address ? (
<button onClick={handleConnect}>Connect Wallet</button>
) : (
<div>
<p>Address: {address}</p>
<p>Contract: {contract ? "Ready" : "Not initialized"}</p>
</div>
)}
</div>
);
}
Making Payments & Signing Transactions
Depositing Funds (Native Token)
To deposit native tokens (CENT) to a smart contract:
async function depositFunds(amountInCENT) {
if (!contract) {
throw new Error("Contract not initialized");
}
try {
// Convert CENT to wei (1 CENT = 10^18 wei)
const value = ethers.utils.parseEther(amountInCENT.toString());
// Call the deposit function with native value
const tx = await contract.deposit({ value });
// Wait for transaction confirmation
await tx.wait();
console.log("Deposit successful:", tx.hash);
return tx;
} catch (err) {
console.error("Deposit failed:", err);
throw err;
}
}
Withdrawing Funds
To withdraw funds from a smart contract:
async function withdrawFunds(amountInCENT) {
if (!contract) {
throw new Error("Contract not initialized");
}
try {
// Convert CENT to wei
const withdrawalAmountWei = ethers.utils.parseEther(amountInCENT.toString());
// Call the withdraw function
const tx = await contract.withdraw(withdrawalAmountWei);
// Show pending transaction notification
console.log("Transaction pending:", tx.hash);
// Wait for confirmation
await tx.wait();
console.log("Withdrawal successful:", tx.hash);
return tx;
} catch (err) {
console.error("Withdrawal failed:", err);
throw err;
}
}
Calling Contract Functions
For any contract function that requires signing:
async function callContractFunction(functionName, ...args) {
if (!contract) {
throw new Error("Contract not initialized");
}
try {
// Call the contract function
const tx = await contract[functionName](...args);
// Wait for transaction
await tx.wait();
console.log("Transaction successful:", tx.hash);
return tx;
} catch (err) {
console.error("Transaction failed:", err);
throw err;
}
}
Reading Contract State (View Functions)
For read-only operations, you don’t need to sign:
async function readContractData(functionName, ...args) {
if (!contract) {
throw new Error("Contract not initialized");
}
try {
// Call view function (no transaction needed)
const result = await contract[functionName](...args);
return result;
} catch (err) {
console.error("Read failed:", err);
throw err;
}
}
Complete Payment Example
import { useState } from "react";
import { IncentivResolver, IncentivSigner } from "@incentiv/dapp-sdk";
import { ethers } from "ethers";
import ABI from "./YourContractABI.json";
import Config from "./config";
function PaymentExample() {
const [address, setAddress] = useState("");
const [contract, setContract] = useState(null);
const [balance, setBalance] = useState(0);
const [isProcessing, setIsProcessing] = useState(false);
// Initialize contract (same as previous example)
async function initializeContract(userAddress) {
const provider = new ethers.providers.JsonRpcProvider(
Config.Environments.Mainnet.RPC
);
const signer = new IncentivSigner({
address: userAddress,
provider: provider,
environment: Config.Environments.Mainnet.Portal,
entryPoint: "[EntryPoint contract address]",
});
const contractInstance = new ethers.Contract(
Config.GamePot.address,
ABI,
signer
);
setContract(contractInstance);
}
// Deposit funds
const handleDeposit = async (amount) => {
if (!contract) return;
setIsProcessing(true);
try {
const value = ethers.utils.parseEther(amount.toString());
const tx = await contract.deposit({ value });
await tx.wait();
console.log("Deposit successful!");
await updateBalance();
} catch (err) {
console.error("Deposit failed:", err);
} finally {
setIsProcessing(false);
}
};
// Withdraw funds
const handleWithdraw = async (amount) => {
if (!contract) return;
setIsProcessing(true);
try {
const amountWei = ethers.utils.parseEther(amount.toString());
const tx = await contract.withdraw(amountWei);
await tx.wait();
console.log("Withdrawal successful!");
await updateBalance();
} catch (err) {
console.error("Withdrawal failed:", err);
} finally {
setIsProcessing(false);
}
};
// Read balance
const updateBalance = async () => {
if (!contract || !address) return;
try {
const balanceWei = await contract.deposits(address);
const balanceCENT = ethers.utils.formatEther(balanceWei);
setBalance(parseFloat(balanceCENT));
} catch (err) {
console.error("Failed to read balance:", err);
}
};
return (
<div>
<button onClick={() => handleConnect()}>Connect Wallet</button>
{contract && (
<div>
<p>Balance: {balance} CENT</p>
<button onClick={() => handleDeposit(10)} disabled={isProcessing}>
Deposit 10 CENT
</button>
<button onClick={() => handleWithdraw(5)} disabled={isProcessing}>
Withdraw 5 CENT
</button>
</div>
)}
</div>
);
}
Complete Code Examples
Full Integration Example
Here’s a complete React component demonstrating the full integration:
import { useEffect, useState, useRef } from "react";
import { IncentivResolver, IncentivSigner } from "@incentiv/dapp-sdk";
import { ethers } from "ethers";
import ABI from "./YourContractABI.json";
import Config from "./config";
function FullIntegrationExample() {
const [address, setAddress] = useState("");
const [contract, setContract] = useState(null);
const [balance, setBalance] = useState(0);
const [isConnecting, setIsConnecting] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const signerRef = useRef(null);
// Initialize contract and signer
async function fetchContractData(userAddress) {
try {
const provider = new ethers.providers.JsonRpcProvider(
Config.Environments.Mainnet.RPC
);
const signer = new IncentivSigner({
address: userAddress,
provider: provider,
environment: Config.Environments.Mainnet.Portal,
entryPoint: "[EntryPoint contract address]",
});
signerRef.current = signer;
const contractInstance = new ethers.Contract(
Config.GamePot.address,
ABI,
signer
);
setContract(contractInstance);
await updateBalance(userAddress, contractInstance);
} catch (err) {
console.error("Failed to initialize contract:", err);
setContract(null);
signerRef.current = null;
}
}
// Connect wallet
const handleConnect = async () => {
setIsConnecting(true);
try {
if (typeof IncentivResolver === "undefined") {
throw new Error("Incentiv wallet extension not found.");
}
const userAddress = await IncentivResolver.getAccountAddress(
Config.Environments.Mainnet.Portal
);
if (!userAddress || userAddress === "null" || userAddress === null) {
throw new Error("No wallet address received.");
}
setAddress(userAddress);
await fetchContractData(userAddress);
} catch (err) {
console.error("Connection error:", err);
alert(`Failed to connect: ${err.message}`);
} finally {
setIsConnecting(false);
}
};
// Update balance
async function updateBalance(userAddr, contractInstance) {
if (!contractInstance || !userAddr) return;
try {
const balanceWei = await contractInstance.deposits(userAddr);
const balanceCENT = ethers.utils.formatEther(balanceWei);
setBalance(parseFloat(balanceCENT));
} catch (err) {
console.error("Failed to read balance:", err);
}
}
// Deposit
const handleDeposit = async (amount) => {
if (!contract) return;
setIsProcessing(true);
try {
const value = ethers.utils.parseEther(amount.toString());
const tx = await contract.deposit({ value });
console.log("Transaction sent:", tx.hash);
await tx.wait();
console.log("Transaction confirmed");
await updateBalance(address, contract);
} catch (err) {
console.error("Deposit failed:", err);
alert(`Deposit failed: ${err.message}`);
} finally {
setIsProcessing(false);
}
};
// Withdraw
const handleWithdraw = async (amount) => {
if (!contract) return;
setIsProcessing(true);
try {
const amountWei = ethers.utils.parseEther(amount.toString());
const tx = await contract.withdraw(amountWei);
console.log("Transaction sent:", tx.hash);
await tx.wait();
console.log("Transaction confirmed");
await updateBalance(address, contract);
} catch (err) {
console.error("Withdrawal failed:", err);
alert(`Withdrawal failed: ${err.message}`);
} finally {
setIsProcessing(false);
}
};
return (
<div style={{ padding: "20px" }}>
<h1>Incentiv SDK Integration</h1>
{!address ? (
<button onClick={handleConnect} disabled={isConnecting}>
{isConnecting ? "Connecting..." : "Connect Wallet"}
</button>
) : (
<div>
<p><strong>Connected:</strong> {address}</p>
<p><strong>Balance:</strong> {balance.toFixed(4)} CENT</p>
<p><strong>Contract Status:</strong> {contract ? "Ready" : "Not initialized"}</p>
<div style={{ marginTop: "20px" }}>
<button
onClick={() => handleDeposit(10)}
disabled={isProcessing}
style={{ marginRight: "10px" }}
>
Deposit 10 CENT
</button>
<button
onClick={() => handleWithdraw(5)}
disabled={isProcessing}
>
Withdraw 5 CENT
</button>
</div>
</div>
)}
</div>
);
}
export default FullIntegrationExample;
Configuration
Network Configuration
Update your configuration based on the network:
Mainnet:
const MainnetConfig = {
Portal: "https://portal.incentiv.io/",
RPC: "https://rpc.incentiv.io",
EntryPoint: "0x..." // Update with mainnet EntryPoint
};
Contract Addresses
Always use checksummed addresses:
const CONTRACT_ADDRESS = "0xC3A195E.....";
Best Practices
1. Error Handling
Always wrap SDK calls in try-catch blocks:
try {
const address = await IncentivResolver.getAccountAddress(portal);
} catch (err) {
// Handle specific error types
if (err.message.includes("extension not found")) {
// Show install wallet message
} else if (err.message.includes("user rejected")) {
// User cancelled the connection
} else {
// Generic error handling
}
}
2. Loading States
Provide user feedback during async operations:
const [isConnecting, setIsConnecting] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
// Use these states to disable buttons and show loading indicators
3. Transaction Confirmation
Always wait for transaction confirmation:
const tx = await contract.deposit({ value });
await tx.wait(); // Wait for confirmation
4. Balance Updates
Update balances after transactions:
await tx.wait();
await updateBalance(); // Refresh balance
5. Address Validation
Validate addresses before using them:
if (!address || address === "null" || address === null) {
throw new Error("Invalid address");
}
6. Contract Initialization Check
Always check if contract is initialized before use:
if (!contract) {
throw new Error("Contract not initialized");
}
7. Use Refs for Signers
Store signer in a ref to avoid re-initialization:
const signerRef = useRef(null);
// Initialize once
signerRef.current = new IncentivSigner({...});
// Use later
const contract = new ethers.Contract(address, ABI, signerRef.current);
Troubleshooting
Issue: “IncentivResolver is undefined”
Solution:
- Ensure the Incentiv wallet extension is installed
- Check that the extension is enabled
- Refresh the page after installing the extension
Issue: “No wallet address received”
Solution:
- Make sure the wallet is unlocked
- Check that the user approved the connection request
- Verify the Portal URL is correct
Issue: Transaction fails with “insufficient funds”
Solution:
- Check the user’s wallet balance
- Ensure enough funds for gas fees
- Verify the amount being sent is correct
Issue: Contract calls fail
Solution:
- Verify the contract address is correct
- Check the ABI matches the contract
- Ensure the signer is properly initialized
- Verify the function name and parameters are correct
Issue: “Provider not found”
Solution:
- Check the RPC URL is correct
- Verify network connectivity
- Test the RPC endpoint directly
Issue: Buffer is not defined
Solution:
- Ensure
buffer is installed: npm install buffer
- Configure Vite as shown in the Project Setup section
- Add buffer to optimizeDeps
API Reference
IncentivResolver
getAccountAddress(portal: string): Promise<string>
Gets the user’s wallet address from the Incentiv wallet extension.
Parameters:
Returns:
Promise<string>: The user’s wallet address
Example:
const address = await IncentivResolver.getAccountAddress(
"https://portal.incentiv.io"
);
IncentivSigner
Constructor
new IncentivSigner({
address: string,
provider: ethers.providers.Provider,
environment: string,
entryPoint: string
})
Parameters:
address: User’s wallet address
provider: Ethers.js provider instance
environment: Portal URL
entryPoint: EntryPoint contract address
Example:
const signer = new IncentivSigner({
address: "0x...",
provider: provider,
environment: "https://portal.incentiv.io",
entryPoint: "[EntryPoint contract address]"
});
Additional Resources
License
This guide is provided as-is for educational purposes. Always refer to the official Incentiv SDK documentation for the most up-to-date information.
Example
Follow this example