Loading...
Role Guide
Investor Guide
Complete guide for trading fund shares on the UFX secondary market. Learn how to create RFQs, review quotes, and manage settlements.
Smart Contract: RFQEngineModule
File: RFQEngineModuleFacet.sol
Role Required: INVESTOR_ROLE
Getting Started
Prerequisites
Before you can trade on UFX, you must complete these one-time setup steps:
●1. Wallet Setup
• Ethereum-compatible wallet (MetaMask, Ledger, etc.)
• Sufficient ETH for gas fees
• Connected to correct network (Sepolia testnet)
• Sufficient ETH for gas fees
• Connected to correct network (Sepolia testnet)
●2. KYC/Identity Verification
• Complete KYC with approved identity provider
• Receive on-chain identity with KYC level
• Credential must be valid and non-expired
• Receive on-chain identity with KYC level
• Credential must be valid and non-expired
●3. Role Grant
• Fund admin grants you INVESTOR_ROLE
• Enables you to create RFQs and accept quotes
• Enables you to create RFQs and accept quotes
●4. Fund Token Holdings
• For selling: Must hold fund tokens you want to sell
• For buying: Must hold payment tokens (e.g., USDC)
• For buying: Must hold payment tokens (e.g., USDC)
Creating an RFQ to Sell Shares
Step 1: Check Fund Details
// Get fund info with latest NAV
const fundData = await ufxViewModule.getFundWithNav(fundId);
console.log("Current NAV:", ethers.formatUnits(fundData.navPerShare, 18));
console.log("Max Premium:", fundData.maxPremiumBps / 100, "%");
console.log("Max Discount:", fundData.maxDiscountBps / 100, "%");
📄 Smart Contract: UfxViewModuleFacet.sol, Function: getFundWithNav()
Step 2: Determine Your Pricing
Example pricing strategy:
Current NAV: $100.00
Max Discount: 2% → Min price: $98.00
Max Premium: 2% → Max price: $102.00
If selling:
• Urgent: Set price at $98.00 (max discount)
• Normal: Set price at $99.00 (1% discount)
• Patient: Set price at $100.00 (at NAV)
Step 3: Create RFQ via Admin Console
1. Navigate to Investor Panel at
/panels2. Click Create RFQ
3. Fill in the form:
• Fund ID: fund-tech-001
• Payment Token: USDC address
• Quantity: 10000 (shares to sell)
• Expected Price: 99.50
• Expiry: 24 hours
4. Submit transaction and confirm in MetaMask
Step 4: Create RFQ via Smart Contract
const tx = await rfqEngineModule.createRFQ(
"fund-tech-001", // fundId
"0xUSDC...", // paymentToken
ethers.parseUnits("10000", 18), // quantity
ethers.parseUnits("99.50", 18), // expectedPrice
Math.floor(Date.now()/1000) + 86400 // expiry (24h)
);
await tx.wait();
console.log("RFQ created successfully!");
📄 Smart Contract: RFQEngineModuleFacet.sol, Function: createRFQ() at line 67
VALIDATION
✓ Fund must be Active
✓ Payment token must be whitelisted
✓ Expected price within NAV ± pricing bounds
✓ You must have valid KYC credential
✓ Expiry must be in the future
✓ Payment token must be whitelisted
✓ Expected price within NAV ± pricing bounds
✓ You must have valid KYC credential
✓ Expiry must be in the future
Reviewing and Accepting Quotes
Viewing Available Quotes
// Get RFQ data including all quotes
const rfqData = await ufxViewModule.getRfqData(rfqId);
console.log("Number of Quotes:", rfqData.quotes.length);
rfqData.quotes.forEach((quote, index) => {
console.log(`Quote $${index + 1}:`);
console.log(" Market Maker:", quote.maker);
console.log(" Price:", ethers.formatUnits(quote.price, 18));
console.log(" Fee:", quote.feeBps / 100, "%");
});
📄 Smart Contract: UfxViewModuleFacet.sol, Function: getRfqData() at line 78
Evaluating Quotes
Compare quotes based on net proceeds (selling) or total cost (buying):
Example: Selling 10,000 shares
Quote A:
Price: $99.00 | Fee: 0.25%
You Receive: $987,525 ✓ BEST
Quote B:
Price: $99.20 | Fee: 0.35%
You Receive: $988,528
Quote C:
Price: $99.50 | Fee: 0.50%
You Receive: $990,025
Accepting a Quote
// Accept quote
const tx = await rfqEngineModule.acceptQuote(rfqId, quoteId);
await tx.wait();
console.log("Quote accepted successfully!");
📄 Smart Contract: RFQEngineModuleFacet.sol, Function: acceptQuote() at line 155
WHAT HAPPENS
✓ Quote still valid (not expired)
✓ RFQ still open (not cancelled/filled)
✓ Compliance rechecked
✓ RFQ status → Filled
✓ Escrow automatically created
✓ RFQ still open (not cancelled/filled)
✓ Compliance rechecked
✓ RFQ status → Filled
✓ Escrow automatically created
Settlement Process
Phase 1: Token Approvals (You Must Do This)
If you're selling fund shares:
// Approve fund tokens
const fundToken = new ethers.Contract(fundTokenAddress, erc20ABI, signer);
const tx = await fundToken.approve(
diamondAddress,
ethers.parseUnits("10000", 18)
);
await tx.wait();
console.log("Fund tokens approved for settlement");
If you're buying fund shares:
// Approve payment tokens (USDC)
const usdc = new ethers.Contract(usdcAddress, erc20ABI, signer);
const tx = await usdc.approve(
diamondAddress,
ethers.parseUnits("150000", 6) // USDC has 6 decimals
);
await tx.wait();
console.log("USDC approved for settlement");
Phase 2: Settlement Execution (Automatic)
Settlement executes automatically by the protocol backend:
SETTLEMENT STEPS
1. Protocol fees deducted
2. Issuer fees deducted
3. Fund tokens transferred: seller → buyer
4. Payment tokens transferred: buyer → seller (minus fees)
5. Compliance exposure updated
6. Registry update queued
2. Issuer fees deducted
3. Fund tokens transferred: seller → buyer
4. Payment tokens transferred: buyer → seller (minus fees)
5. Compliance exposure updated
6. Registry update queued
📄 Smart Contract: SettlementModuleFacet.sol, Function: settleEscrow() at line 145
Common Scenarios
Selling for Liquidity (Urgent)
Situation: You need USDC within 24 hours
Strategy:
• Set expected price at max discount (2% below NAV)
• Set short expiry (6 hours)
• Accept first reasonable quote quickly
• Approve tokens immediately after acceptance
Expected Outcome: Fast response from market makers, quick settlement, slightly lower proceeds
Strategy:
• Set expected price at max discount (2% below NAV)
• Set short expiry (6 hours)
• Accept first reasonable quote quickly
• Approve tokens immediately after acceptance
Expected Outcome: Fast response from market makers, quick settlement, slightly lower proceeds
What if my KYC expires during a trade?
The trade will be rejected with a "CredentialExpired" error. Contact your identity provider to renew your KYC credential, then retry accepting the quote (if still valid).
Settlement fails with "InsufficientBalance"
Cause: You don't have enough tokens after approval
Solution: Check your balance before proceeding:
Solution: Check your balance before proceeding:
const balance = await fundToken.balanceOf(yourAddress);
console.log("Have:", ethers.formatUnits(balance, 18));
console.log("Need:", "10000");