| 
 | 1 | +# Ramp Plugin Architecture  | 
 | 2 | + | 
 | 3 | +This document describes the simplified ramp plugin architecture for Edge React GUI, focusing on the streamlined approach after removing the `getSupportedAssets` method.  | 
 | 4 | + | 
 | 5 | +## Overview  | 
 | 6 | + | 
 | 7 | +The ramp plugin system provides a unified interface for integrating fiat on/off ramp providers (buy/sell cryptocurrency). The architecture has been simplified to reduce complexity and improve performance.  | 
 | 8 | + | 
 | 9 | +## Architecture Flow  | 
 | 10 | + | 
 | 11 | +### Previous Architecture (Complex)  | 
 | 12 | +1. User selects crypto/fiat pair  | 
 | 13 | +2. UI calls `useSupportedPlugins` hook  | 
 | 14 | +3. Hook calls `getSupportedAssets` on each plugin  | 
 | 15 | +4. UI filters to only supported plugins  | 
 | 16 | +5. UI calls `fetchQuote` on supported plugins only  | 
 | 17 | +6. Display quotes to user  | 
 | 18 | + | 
 | 19 | +### Current Architecture (Simplified)  | 
 | 20 | +1. User selects crypto/fiat pair  | 
 | 21 | +2. UI gets all plugins from Redux  | 
 | 22 | +3. UI calls `fetchQuote` on all plugins in parallel  | 
 | 23 | +4. Plugins return empty array if unsupported  | 
 | 24 | +5. Display quotes to user  | 
 | 25 | + | 
 | 26 | +## Plugin Interface  | 
 | 27 | + | 
 | 28 | +```typescript  | 
 | 29 | +export interface RampPlugin {  | 
 | 30 | +  readonly pluginId: string  | 
 | 31 | +  readonly rampInfo: RampInfo  | 
 | 32 | + | 
 | 33 | +  readonly fetchQuote: (  | 
 | 34 | +    request: RampQuoteRequest,  | 
 | 35 | +    opts?: unknown  | 
 | 36 | +  ) => Promise<RampQuoteResult[]>  | 
 | 37 | +}  | 
 | 38 | +```  | 
 | 39 | + | 
 | 40 | +### Key Changes  | 
 | 41 | +- Removed `getSupportedAssets` method  | 
 | 42 | +- All support checking happens inside `fetchQuote`  | 
 | 43 | +- Return empty array `[]` for unsupported requests  | 
 | 44 | +- Only throw errors for actual failures  | 
 | 45 | + | 
 | 46 | +## Implementation Guide  | 
 | 47 | + | 
 | 48 | +### Creating a Ramp Plugin  | 
 | 49 | + | 
 | 50 | +```typescript  | 
 | 51 | +export const myRampPlugin: RampPluginFactory = (config: RampPluginConfig) => {  | 
 | 52 | +  const { account, navigation, onLogEvent, disklet } = config  | 
 | 53 | +    | 
 | 54 | +  const plugin: RampPlugin = {  | 
 | 55 | +    pluginId: 'myplugin',  | 
 | 56 | +    rampInfo: {  | 
 | 57 | +      partnerIcon: 'https://example.com/icon.png',  | 
 | 58 | +      pluginDisplayName: 'My Plugin'  | 
 | 59 | +    },  | 
 | 60 | +      | 
 | 61 | +    fetchQuote: async (request: RampQuoteRequest): Promise<RampQuoteResult[]> => {  | 
 | 62 | +      const {  | 
 | 63 | +        direction,  | 
 | 64 | +        regionCode,  | 
 | 65 | +        fiatCurrencyCode,  | 
 | 66 | +        displayCurrencyCode,  | 
 | 67 | +        tokenId,  | 
 | 68 | +        pluginId: currencyPluginId  | 
 | 69 | +      } = request  | 
 | 70 | +        | 
 | 71 | +      // 1. Check region support  | 
 | 72 | +      if (!isRegionSupported(regionCode)) {  | 
 | 73 | +        return [] // Not supported  | 
 | 74 | +      }  | 
 | 75 | +        | 
 | 76 | +      // 2. Check asset support  | 
 | 77 | +      if (!isAssetSupported(currencyPluginId, tokenId)) {  | 
 | 78 | +        return [] // Not supported  | 
 | 79 | +      }  | 
 | 80 | +        | 
 | 81 | +      // 3. Check fiat support  | 
 | 82 | +      if (!isFiatSupported(fiatCurrencyCode)) {  | 
 | 83 | +        return [] // Not supported  | 
 | 84 | +      }  | 
 | 85 | +        | 
 | 86 | +      // 4. Fetch quotes from provider  | 
 | 87 | +      try {  | 
 | 88 | +        const quotes = await fetchFromProvider(request)  | 
 | 89 | +        return quotes.map(quote => convertToRampQuoteResult(quote))  | 
 | 90 | +      } catch (error) {  | 
 | 91 | +        // Only throw for actual errors  | 
 | 92 | +        console.error(`Failed to fetch quotes: ${error}`)  | 
 | 93 | +        throw error  | 
 | 94 | +      }  | 
 | 95 | +    }  | 
 | 96 | +  }  | 
 | 97 | +    | 
 | 98 | +  return plugin  | 
 | 99 | +}  | 
 | 100 | +```  | 
 | 101 | + | 
 | 102 | +## UI Integration  | 
 | 103 | + | 
 | 104 | +### TradeCreateScene  | 
 | 105 | + | 
 | 106 | +```typescript  | 
 | 107 | +export const TradeCreateScene = () => {  | 
 | 108 | +  // Get all plugins directly from Redux  | 
 | 109 | +  const rampPlugins = useSelector(state => state.rampPlugins.plugins)  | 
 | 110 | +  const isPluginsLoading = useSelector(state => state.rampPlugins.isLoading)  | 
 | 111 | +    | 
 | 112 | +  // Create quote request  | 
 | 113 | +  const rampQuoteRequest: RampQuoteRequest = {  | 
 | 114 | +    // ... request parameters  | 
 | 115 | +  }  | 
 | 116 | +    | 
 | 117 | +  // Fetch quotes from all plugins  | 
 | 118 | +  const { quotes, isLoading, errors } = useRampQuotes({  | 
 | 119 | +    rampQuoteRequest,  | 
 | 120 | +    plugins: rampPlugins  | 
 | 121 | +  })  | 
 | 122 | +    | 
 | 123 | +  // Render UI  | 
 | 124 | +  return (  | 
 | 125 | +    // ... UI components  | 
 | 126 | +  )  | 
 | 127 | +}  | 
 | 128 | +```  | 
 | 129 | + | 
 | 130 | +### useRampQuotes Hook  | 
 | 131 | + | 
 | 132 | +The hook handles:  | 
 | 133 | +- Parallel quote fetching from all plugins  | 
 | 134 | +- Filtering out empty results (unsupported)  | 
 | 135 | +- Error handling and retry logic  | 
 | 136 | +- Quote expiration and refresh  | 
 | 137 | +- Result caching and deduplication  | 
 | 138 | + | 
 | 139 | +## Benefits of Simplified Architecture  | 
 | 140 | + | 
 | 141 | +1. **Performance**: All plugins check support and fetch quotes in a single parallel operation  | 
 | 142 | +2. **Simplicity**: One method to implement instead of two  | 
 | 143 | +3. **Reduced Latency**: No sequential support check followed by quote fetch  | 
 | 144 | +4. **Better Error Handling**: Clear distinction between "not supported" (empty array) and "error" (exception)  | 
 | 145 | +5. **Easier Testing**: Only one method to test per plugin  | 
 | 146 | +6. **Less Code**: Removed entire `useSupportedPlugins` hook and related logic  | 
 | 147 | + | 
 | 148 | +## Migration from Legacy Architecture  | 
 | 149 | + | 
 | 150 | +See [Ramp Plugin Migration Guide](./ramp-plugin-migration-guide.md) for detailed migration instructions.  | 
 | 151 | + | 
 | 152 | +## Best Practices  | 
 | 153 | + | 
 | 154 | +1. **Return Empty Array**: Always return `[]` for unsupported requests, never throw  | 
 | 155 | +2. **Fast Fail**: Check support conditions early in `fetchQuote` to avoid unnecessary API calls  | 
 | 156 | +3. **Parallel Processing**: The UI fetches from all plugins in parallel, so optimize for quick responses  | 
 | 157 | +4. **Error Logging**: Log support check failures for debugging but don't throw  | 
 | 158 | +5. **Cache Support Data**: Cache any expensive support checks within the plugin if needed  | 
 | 159 | + | 
 | 160 | +## Example Quote Flow  | 
 | 161 | + | 
 | 162 | +```mermaid  | 
 | 163 | +sequenceDiagram  | 
 | 164 | +    participant User  | 
 | 165 | +    participant UI  | 
 | 166 | +    participant Redux  | 
 | 167 | +    participant Plugin1  | 
 | 168 | +    participant Plugin2  | 
 | 169 | +      | 
 | 170 | +    User->>UI: Select crypto/fiat pair  | 
 | 171 | +    UI->>Redux: Get all plugins  | 
 | 172 | +    Redux->>UI: Return plugins  | 
 | 173 | +      | 
 | 174 | +    par Parallel Execution  | 
 | 175 | +        UI->>Plugin1: fetchQuote(request)  | 
 | 176 | +        UI->>Plugin2: fetchQuote(request)  | 
 | 177 | +    end  | 
 | 178 | +      | 
 | 179 | +    Plugin1->>UI: Return quotes or []  | 
 | 180 | +    Plugin2->>UI: Return quotes or []  | 
 | 181 | +      | 
 | 182 | +    UI->>User: Display available quotes  | 
 | 183 | +```  | 
 | 184 | + | 
 | 185 | +## Plugin State Management  | 
 | 186 | + | 
 | 187 | +Plugins are initialized once when the app starts and stored in Redux:  | 
 | 188 | + | 
 | 189 | +```typescript  | 
 | 190 | +interface RampPluginState {  | 
 | 191 | +  readonly isLoading: boolean  | 
 | 192 | +  readonly plugins: Record<string, RampPlugin>  | 
 | 193 | +}  | 
 | 194 | +```  | 
 | 195 | + | 
 | 196 | +The `RampPluginManager` component handles:  | 
 | 197 | +- Loading plugin factories  | 
 | 198 | +- Initializing plugins with configuration  | 
 | 199 | +- Updating Redux state when ready  | 
 | 200 | + | 
 | 201 | +## Future Considerations  | 
 | 202 | + | 
 | 203 | +1. **Plugin Discovery**: Dynamic plugin loading based on user region  | 
 | 204 | +2. **Quote Caching**: Shared quote cache across plugins  | 
 | 205 | +3. **WebSocket Support**: Real-time quote updates  | 
 | 206 | +4. **Plugin Versioning**: Support for multiple plugin versions  | 
 | 207 | +5. **Analytics**: Unified analytics across all plugins  | 
0 commit comments