This guide will walk you through the process of integrating your project with Curvance's plugin architecture, allowing your application to interact with Curvance's smart contracts on behalf of users.
For an in-depth exploration of the Plugin and Delegation system architecture, check out our technical documentation page:
Understanding Plugin Delegation
Curvance's plugin system enables third-party applications to perform actions on behalf of users through a secure delegation mechanism. This allows for innovative features like:
Automated portfolio management
Advanced trading strategies
Cross-chain operations
Reward auto-compounding
Sequential action chaining
User Delegation Setup
Before your application can act on behalf of users, they must explicitly authorize your contract address as a delegate. This is the critical first step in the integration process.
Enabling Delegation with setDelegateApproval()
Users need to call the setDelegateApproval() function on the appropriate Curvance contract.
Calling setDelegateApproval() is called correctly with these arguments:
Type
Name
Instruction
address
delegate
The address of your platform's contract
bool
isApproved
To activate delegation of your platform, this would be true
Below is an example showing how to implement this using Ethers.js 5.7 for a position that uses PositionManagementSimple (such as pwstETH):
const { ethers } = require("ethers");
// Import your project's contract address
const { YourProject_Address } = require("./config/addresses");
// Import pwstETH Position Management contract address from a config file
const { pwstETH_PositionManagement_Address } = require("./config/addresses");
// Import ABI from a separate file
const { pwstETH_PositionManagement_ABI } = require("./abis/pwstETHABI");
// Connect to provider (adjust as needed for your environment)
const provider = new ethers.providers.Web3Provider(window.ethereum);
// Or for a specific RPC endpoint:
// const provider = new ethers.providers.JsonRpcProvider("YOUR_RPC_URL");
// Create signer
const signer = provider.getSigner();
// Create contract instance using imported address, ABI, and signer
const pwstETHPositionManagementContract = new ethers.Contract(
pwstETH_PositionManagement_Address,
pwstETH_PositionManagement_ABI,
signer
);
async function approveDelegate() {
try {
// Call the setDelegateApproval function
const tx = await pwstETHPositionManagementContract.setDelegateApproval(
YourProject_Address,
true);
console.log("Transaction submitted:", tx.hash);
// Wait for transaction to be mined
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
return receipt;
} catch (error) {
console.error("Error approving delegate:", error);
// Handle specific errors
if (error.code === 'CALL_EXCEPTION') {
if (error.reason && error.reason.includes("PluginDelegable__DelegatingDisabled")) {
console.error("Delegation is disabled for this account");
} else if (error.reason && error.reason.includes("PluginDelegable_InvalidParameter")) {
console.error("Invalid parameter: Cannot delegate to yourself");
}
}
throw error;
}
}
Verification and Security Best Practices
When implementing delegation in your application:
Verify delegation status: Always check if your contract is still approved as a delegate before attempting actions by calling isDelegate()in the CentralRegistry contract using the following parameters:
Type
Name
Description
address
user
The user's address
address
delegate
Your platform's contract address
const { ethers } = require("ethers");
// Import your project's contract address
const { YourProject_Address } = require("./config/addresses");
// Import CentralRegistry contract address from a config file
const { CentralRegistryAddress } = require("./config/addresses");
// Import ABI from a separate file
const { CentralRegistry_ABI } = require("./abis/centralRegistryABI");
// Connect to provider (adjust as needed for your environment)
const provider = new ethers.providers.Web3Provider(window.ethereum);
// Or for a specific RPC endpoint:
// const provider = new ethers.providers.JsonRpcProvider("YOUR_RPC_URL");
// Create signer
const signer = provider.getSigner();
// Create contract instance using imported address, ABI, and signer
const CentralRegistry_Contract = new ethers.Contract(
CentralRegistryAddress,
CentralRegistry_ABI,
signer
);
async function checkDelegate() {
try {
// Call the isDelegate function
const isDelegate = await CentralRegistry_Contract.isDelegate(
userAddress,
true);
console.log("isDelegate: ", isDelegate);
} catch (error) {
console.error("Error approving delegate:", error);
throw error;
}
}
Handle revocation: Users can revoke delegation at any time, so design your application to gracefully handle this case
Transparent permissions: Clearly communicate to users which actions your application will perform on their behalf
Gas optimization: Consider batching multiple delegated actions when possible to reduce gas costs
Next Steps
After implementing the delegation setup, your application should:
Verify the delegation was successful
Store the user's delegation status in your application state
Implement the specific delegated actions your application needs
Provide a way for users to revoke delegation if desired
For technical support or to get your plugin featured in Curvance's ecosystem, please contact our developer relations team.