11import { assert } from '@0x/assert' ;
22import { ERC20BridgeSource } from '@0x/asset-swapper' ;
33
4+ import { ValidationError , ValidationErrorCodes , ValidationErrorReasons } from '../errors' ;
45import {
56 MetaTransactionDailyLimiterConfig ,
67 MetaTransactionRateLimitConfig ,
@@ -10,7 +11,124 @@ import {
1011
1112import { AvailableRateLimiter , DatabaseKeysUsedForRateLimiter , RollingLimiterIntervalUnit } from './rate-limiters' ;
1213
14+ interface ParseRequestForExcludedSourcesParams {
15+ takerAddress ?: string ;
16+ excludedSources ?: string ;
17+ includedSources ?: string ;
18+ intentOnFilling ?: string ;
19+ apiKey ?: string ;
20+ }
21+
22+ /**
23+ * This constant contains, as keys, all ERC20BridgeSource types except from `Native`.
24+ * As we add more bridge sources to AssetSwapper, we want to keep ourselves accountable to add
25+ * them to this constant. Since there isn't a good way to enumerate over enums, we use a obect type.
26+ * The type has been defined in a way that the code won't compile if a new ERC20BridgeSource is added.
27+ */
28+ const ALL_EXCEPT_NATIVE : { [ key in Exclude < ERC20BridgeSource , ERC20BridgeSource . Native > ] : boolean } = {
29+ Uniswap : true ,
30+ Balancer : true ,
31+ Curve : true ,
32+ Eth2Dai : true ,
33+ Kyber : true ,
34+ LiquidityProvider : true ,
35+ MultiBridge : true ,
36+ Uniswap_V2 : true ,
37+ } ;
38+
1339export const parseUtils = {
40+ parseRequestForExcludedSources (
41+ request : ParseRequestForExcludedSourcesParams ,
42+ validApiKeys : string [ ] ,
43+ endpoint : 'price' | 'quote' ,
44+ ) : { excludedSources : ERC20BridgeSource [ ] ; nativeExclusivelyRFQT : boolean } {
45+ // Ensure that both filtering arguments cannot be present.
46+ if ( request . excludedSources !== undefined && request . includedSources !== undefined ) {
47+ throw new ValidationError ( [
48+ {
49+ field : 'excludedSources' ,
50+ code : ValidationErrorCodes . IncorrectFormat ,
51+ reason : ValidationErrorReasons . ConflictingFilteringArguments ,
52+ } ,
53+ {
54+ field : 'includedSources' ,
55+ code : ValidationErrorCodes . IncorrectFormat ,
56+ reason : ValidationErrorReasons . ConflictingFilteringArguments ,
57+ } ,
58+ ] ) ;
59+ }
60+
61+ // If excludedSources is present, parse the string array and return
62+ if ( request . excludedSources !== undefined ) {
63+ return {
64+ excludedSources : parseUtils . parseStringArrForERC20BridgeSources ( request . excludedSources . split ( ',' ) ) ,
65+ nativeExclusivelyRFQT : false ,
66+ } ;
67+ }
68+
69+ if ( request . includedSources !== undefined ) {
70+ // Only RFQT is eligible as of now
71+ if ( request . includedSources === 'RFQT' ) {
72+ // We assume that if a `takerAddress` key is present, it's value was already validated by the JSON
73+ // schema.
74+ if ( request . takerAddress === undefined ) {
75+ throw new ValidationError ( [
76+ {
77+ field : 'takerAddress' ,
78+ code : ValidationErrorCodes . RequiredField ,
79+ reason : ValidationErrorReasons . TakerAddressInvalid ,
80+ } ,
81+ ] ) ;
82+ }
83+
84+ // We enforce a valid API key - we don't want to fail silently.
85+ if ( request . apiKey === undefined ) {
86+ throw new ValidationError ( [
87+ {
88+ field : '0x-api-key' ,
89+ code : ValidationErrorCodes . RequiredField ,
90+ reason : ValidationErrorReasons . InvalidApiKey ,
91+ } ,
92+ ] ) ;
93+ }
94+ if ( ! validApiKeys . includes ( request . apiKey ) ) {
95+ throw new ValidationError ( [
96+ {
97+ field : '0x-api-key' ,
98+ code : ValidationErrorCodes . FieldInvalid ,
99+ reason : ValidationErrorReasons . InvalidApiKey ,
100+ } ,
101+ ] ) ;
102+ }
103+
104+ // If the user is requesting a firm quote, we want to make sure that `intentOnFilling` is set to "true".
105+ if ( endpoint === 'quote' && request . intentOnFilling !== 'true' ) {
106+ throw new ValidationError ( [
107+ {
108+ field : 'intentOnFilling' ,
109+ code : ValidationErrorCodes . RequiredField ,
110+ reason : ValidationErrorReasons . RequiresIntentOnFilling ,
111+ } ,
112+ ] ) ;
113+ }
114+
115+ return {
116+ nativeExclusivelyRFQT : true ,
117+ excludedSources : Object . keys ( ALL_EXCEPT_NATIVE ) as ERC20BridgeSource [ ] ,
118+ } ;
119+ } else {
120+ throw new ValidationError ( [
121+ {
122+ field : 'includedSources' ,
123+ code : ValidationErrorCodes . IncorrectFormat ,
124+ reason : ValidationErrorReasons . ArgumentNotYetSupported ,
125+ } ,
126+ ] ) ;
127+ }
128+ }
129+
130+ return { excludedSources : [ ] , nativeExclusivelyRFQT : false } ;
131+ } ,
14132 parseStringArrForERC20BridgeSources ( excludedSources : string [ ] ) : ERC20BridgeSource [ ] {
15133 // Need to compare value of the enum instead of the key, as values are used by asset-swapper
16134 // CurveUsdcDaiUsdt = 'Curve_USDC_DAI_USDT' is excludedSources=Curve_USDC_DAI_USDT
0 commit comments