Comprehensive asset issuer verification system for SwiftRemit that validates Stellar assets against multiple trusted sources.
The asset verification system provides a hybrid approach combining on-chain storage with off-chain verification services to ensure asset safety and build trust in the remittance platform.
-
Smart Contract (Soroban)
- Stores verification results on-chain
- Provides query functions for verification status
- Validates asset safety before transactions
- Admin-controlled verification updates
-
Backend Service (Node.js/TypeScript)
- AssetVerifier service for multi-source verification
- PostgreSQL database for caching and persistence
- RESTful API for verification queries
- Background job scheduler for periodic revalidation
-
Frontend Component (React)
- VerificationBadge component for visual indicators
- Detailed verification information modals
- Warning system for suspicious assets
- Community reporting functionality
-
Stellar Expert
- Asset rating and age
- Community trust indicators
- Score: 0-100 based on rating
-
Stellar TOML
- Home domain validation
- TOML file structure check
- Documentation presence
- Score: 80 if valid, 30 if partial, 0 if missing
-
Trustline Analysis
- Number of accounts holding the asset
- Score: 100 (10k+), 80 (1k+), 60 (100+), 40 (10+), 20 (<10)
-
Transaction History
- Recent activity (last 30 days)
- Historical transaction count
- Score: 70 (recent + historical), 50 (historical only), 30 (recent only)
reputation_score = average(verified_source_scores)
- Verified: Score ≥ 70 AND ≥ 3 sources verified
- Suspicious: Score < 30 OR suspicious indicators detected
- Unverified: All other cases
- No stellar.toml file
- < 5 trustlines
- No transaction history
- Multiple community reports (≥ 5)
pub fn set_asset_verification(
env: Env,
asset_code: String,
issuer: Address,
status: VerificationStatus,
reputation_score: u32,
trustline_count: u64,
has_toml: bool,
) -> Result<(), ContractError>Stores or updates asset verification data. Admin only.
pub fn get_asset_verification(
env: Env,
asset_code: String,
issuer: Address,
) -> Result<AssetVerification, ContractError>Retrieves verification data for an asset.
pub fn has_asset_verification(
env: Env,
asset_code: String,
issuer: Address,
) -> boolChecks if verification data exists.
pub fn validate_asset_safety(
env: Env,
asset_code: String,
issuer: Address,
) -> Result<(), ContractError>Validates that an asset is not flagged as suspicious.
Retrieve verification status for an asset.
Response:
{
"asset_code": "USDC",
"issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
"status": "verified",
"reputation_score": 95,
"last_verified": "2026-02-23T10:30:00Z",
"trustline_count": 15000,
"has_toml": true,
"stellar_expert_verified": true,
"community_reports": 0
}Trigger new verification for an asset.
Request:
{
"assetCode": "USDC",
"issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
}Report suspicious asset.
Request:
{
"assetCode": "SCAM",
"issuer": "GXXX...",
"reason": "Phishing attempt"
}List verified assets.
Query Parameters:
limit: Max results (default: 100, max: 500)
Batch verification lookup (max 50 assets).
Request:
{
"assets": [
{ "assetCode": "USDC", "issuer": "GA5Z..." },
{ "assetCode": "BTC", "issuer": "GBXX..." }
]
}import { VerificationBadge } from './components/VerificationBadge';
function AssetDisplay() {
return (
<div>
<h3>USDC</h3>
<VerificationBadge
assetCode="USDC"
issuer="GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
apiUrl="http://localhost:3000"
/>
</div>
);
}<VerificationBadge
assetCode="UNKNOWN"
issuer="GXXX..."
onWarning={(verification) => {
console.warn('Asset warning:', verification);
// Show custom warning UI
}}
/>CREATE TABLE verified_assets (
id SERIAL PRIMARY KEY,
asset_code VARCHAR(12) NOT NULL,
issuer VARCHAR(56) NOT NULL,
status VARCHAR(20) NOT NULL,
reputation_score INTEGER NOT NULL CHECK (reputation_score >= 0 AND reputation_score <= 100),
last_verified TIMESTAMP NOT NULL DEFAULT NOW(),
trustline_count BIGINT NOT NULL DEFAULT 0,
has_toml BOOLEAN NOT NULL DEFAULT FALSE,
stellar_expert_verified BOOLEAN DEFAULT FALSE,
toml_data JSONB,
community_reports INTEGER DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE(asset_code, issuer)
);- Asset code: Max 12 characters
- Issuer: Exactly 56 characters (Stellar address format)
- Reputation score: 0-100 range enforced
- Report reason: Max 500 characters
- 100 requests per 15 minutes per IP
- Configurable via environment variables
- Unique constraint on (asset_code, issuer)
- Community report threshold (5 reports → suspicious)
- Admin-only on-chain updates
- Request timeouts and retries
- 5-second timeout per request
- 3 retry attempts with exponential backoff
- Error handling for malformed responses
- Graceful degradation on source failures
- Runs every 6 hours
- Revalidates assets older than 24 hours
- Updates both database and on-chain storage
- Rate-limited to 1 asset per second
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/swiftremit
# Stellar
STELLAR_NETWORK=testnet
HORIZON_URL=https://horizon-testnet.stellar.org
CONTRACT_ID=CXXX...
ADMIN_SECRET_KEY=SXXX...
# API
PORT=3000
NODE_ENV=development
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# Verification
VERIFICATION_INTERVAL_HOURS=24
MIN_TRUSTLINE_COUNT=10
MIN_REPUTATION_SCORE=50cd backend
npm install
cp .env.example .env
# Edit .env with your configuration
npm run build
npm start# PostgreSQL must be running
psql -U postgres -c "CREATE DATABASE swiftremit;"
# Tables are created automatically on first run# Build contract
cargo build --target wasm32-unknown-unknown --release
soroban contract optimize --wasm target/wasm32-unknown-unknown/release/swiftremit.wasm
# Deploy
soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/swiftremit.optimized.wasm \
--source deployer \
--network testnetcd backend
npm testcargo test# Start backend service
cd backend && npm start
# Run integration tests
npm run test:integrationAssetNotFound (13): Asset not in verification databaseInvalidReputationScore (14): Score not in 0-100 rangeSuspiciousAsset (15): Asset flagged as suspicious
400: Invalid input parameters404: Asset verification not found429: Rate limit exceeded500: Internal server error
- Database indexes on (asset_code, issuer), status, last_verified
- Verification results cached in database
- On-chain storage for critical data only
- Batch API for multiple asset lookups
- Background jobs prevent blocking user requests
- Machine learning for fraud detection
- Integration with additional anchor registries
- Real-time event streaming for verification updates
- Multi-network support (mainnet, testnet)
- Advanced analytics dashboard
- Automated dispute resolution
- Reputation decay over time
- Weighted scoring based on source reliability
For issues or questions:
- GitHub Issues: Report issues
- Documentation: See this file and inline code comments
- Stellar Discord: https://discord.gg/stellar