Skip to content

Commit ae2fe55

Browse files
author
Cece Z
authored
[TKR-275] Add Geist on Fantom (0xProject#398)
* Add Geist on Fantom * nvm there is not subgraph for it * finish giest utils * Address pr comments * lowercase gtoken addresses * return undefined instead of error for unsupported pairs * another lower case * Update fantom fillQuoteTransformer address * more const clean up
1 parent 6073607 commit ae2fe55

File tree

10 files changed

+207
-146
lines changed

10 files changed

+207
-146
lines changed

packages/asset-swapper/CHANGELOG.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
[
2+
3+
{
4+
"version": "16.50.0",
5+
"changes": [
6+
{
7+
"note": "Adding support for Geist on `Fantom`",
8+
"pr": 398
9+
}
10+
]
11+
},
212
{
313
"version": "16.49.9",
414
"changes": [
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { BigNumber } from '@0x/utils';
2+
3+
import { ZERO_AMOUNT } from '../constants';
4+
export interface GeistInfo {
5+
lendingPool: string;
6+
gToken: string;
7+
underlyingToken: string;
8+
}
9+
// tslint:disable-next-line:no-unnecessary-class
10+
export class GeistSampler {
11+
public static sampleSellsFromGeist(
12+
geistInfo: GeistInfo,
13+
takerToken: string,
14+
makerToken: string,
15+
takerTokenAmounts: BigNumber[],
16+
): BigNumber[] {
17+
// Deposit/Withdrawal underlying <-> gToken is always 1:1
18+
if (
19+
(takerToken.toLowerCase() === geistInfo.gToken.toLowerCase() &&
20+
makerToken.toLowerCase() === geistInfo.underlyingToken.toLowerCase()) ||
21+
(takerToken.toLowerCase() === geistInfo.underlyingToken.toLowerCase() &&
22+
makerToken.toLowerCase() === geistInfo.gToken.toLowerCase())
23+
) {
24+
return takerTokenAmounts;
25+
}
26+
27+
// Not matching the reserve return 0 results
28+
const numSamples = takerTokenAmounts.length;
29+
30+
const makerTokenAmounts = new Array(numSamples);
31+
makerTokenAmounts.fill(ZERO_AMOUNT);
32+
return makerTokenAmounts;
33+
}
34+
35+
public static sampleBuysFromGeist(
36+
geistInfo: GeistInfo,
37+
takerToken: string,
38+
makerToken: string,
39+
makerTokenAmounts: BigNumber[],
40+
): BigNumber[] {
41+
// Deposit/Withdrawal underlying <-> gToken is always 1:1
42+
if (
43+
(takerToken.toLowerCase() === geistInfo.gToken.toLowerCase() &&
44+
makerToken.toLowerCase() === geistInfo.underlyingToken.toLowerCase()) ||
45+
(takerToken.toLowerCase() === geistInfo.underlyingToken.toLowerCase() &&
46+
makerToken.toLowerCase() === geistInfo.gToken.toLowerCase())
47+
) {
48+
return makerTokenAmounts;
49+
}
50+
51+
// Not matching the reserve return 0 results
52+
const numSamples = makerTokenAmounts.length;
53+
const takerTokenAmounts = new Array(numSamples);
54+
takerTokenAmounts.fill(ZERO_AMOUNT);
55+
return takerTokenAmounts;
56+
}
57+
}

packages/asset-swapper/src/utils/market_operation_utils/constants.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
ERC20BridgeSource,
1818
FeeSchedule,
1919
FillData,
20+
GeistFillData,
2021
GetMarketOrdersOpts,
2122
KyberSamplerOpts,
2223
LidoInfo,
@@ -187,6 +188,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
187188
ERC20BridgeSource.Beethovenx,
188189
ERC20BridgeSource.Curve,
189190
ERC20BridgeSource.CurveV2,
191+
ERC20BridgeSource.Geist,
190192
ERC20BridgeSource.JetSwap,
191193
ERC20BridgeSource.MorpheusSwap,
192194
ERC20BridgeSource.SpiritSwap,
@@ -331,6 +333,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
331333
ERC20BridgeSource.Beethovenx,
332334
ERC20BridgeSource.Curve,
333335
ERC20BridgeSource.CurveV2,
336+
ERC20BridgeSource.Geist,
334337
ERC20BridgeSource.JetSwap,
335338
ERC20BridgeSource.MorpheusSwap,
336339
ERC20BridgeSource.SpiritSwap,
@@ -578,6 +581,7 @@ export const FANTOM_TOKENS = {
578581
DAI: '0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e',
579582
fUSDT: '0x049d68029688eabf473097a2fc38ef61633a3c7a',
580583
WBTC: '0x321162cd933e2be498cd2267a90534a804051b11',
584+
WCRV: '0x1e4f97b9f9f913c46f1632781732927b9019c68b',
581585
renBTC: '0xdbf31df14b66535af65aac99c32e9ea844e14501',
582586
MIM: '0x82f0b8b456c1a451378467398982d4834b6829c1',
583587
nUSD: '0xed2a7edd7413021d440b09d654f3b87712abab66',
@@ -586,6 +590,15 @@ export const FANTOM_TOKENS = {
586590
gUSDC: '0xe578c856933d8e1082740bf7661e379aa2a30b26',
587591
gDAI: '0x07e6332dd090d287d3489245038daf987955dcfb',
588592
FRAX: '0xdc301622e621166bd8e82f2ca0a26c13ad0be355',
593+
gFTM: '0x39b3bd37208cbade74d0fcbdbb12d606295b430a',
594+
gETH: '0x25c130b2624cf12a4ea30143ef50c5d68cefa22f',
595+
gWBTC: '0x38aca5484b8603373acc6961ecd57a6a594510a3',
596+
gCRV: '0x690754a168b022331caa2467207c61919b3f8a98',
597+
gMIM: '0xc664fc7b8487a3e10824cda768c1d239f2403bbe',
598+
};
599+
600+
export const GEIST_FANTOM_POOLS = {
601+
lendingPool: '0x9fad24f572045c7869117160a571b2e50b10d068',
589602
};
590603

591604
export const OPTIMISM_TOKENS = {
@@ -1996,6 +2009,13 @@ export const COMPONENT_POOLS_BY_CHAIN_ID = valueByChainId(
19962009
},
19972010
);
19982011

2012+
export const GEIST_INFO_ADDRESS_BY_CHAIN_ID = valueByChainId<string>(
2013+
{
2014+
[ChainId.Fantom]: '0xd8321aa83fb0a4ecd6348d4577431310a6e0814d',
2015+
},
2016+
NULL_ADDRESS,
2017+
);
2018+
19992019
export const BALANCER_V2_VAULT_ADDRESS_BY_CHAIN = valueByChainId<string>(
20002020
{
20012021
[ChainId.Mainnet]: '0xba12222222228d8ba445958a75a0704d566bf2c8',
@@ -2362,6 +2382,10 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
23622382
// NOTE: The Aave deposit method is more expensive than the withdraw
23632383
return aaveFillData.takerToken === aaveFillData.underlyingToken ? 400e3 : 300e3;
23642384
},
2385+
[ERC20BridgeSource.Geist]: (fillData?: FillData) => {
2386+
const geistFillData = fillData as GeistFillData;
2387+
return geistFillData.takerToken === geistFillData.underlyingToken ? 400e3 : 300e3;
2388+
},
23652389
[ERC20BridgeSource.Compound]: (fillData?: FillData) => {
23662390
// NOTE: cETH is handled differently than other cTokens
23672391
const wethAddress = NATIVE_FEE_TOKEN_BY_CHAIN_ID[ChainId.Mainnet];
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { FANTOM_TOKENS, GEIST_FANTOM_POOLS } from './constants';
2+
import { GeistInfo } from './types';
3+
4+
const gTokenToUnderlyingToken = new Map<string, string>([
5+
[FANTOM_TOKENS.gFTM, FANTOM_TOKENS.WFTM],
6+
[FANTOM_TOKENS.gfUSDT, FANTOM_TOKENS.fUSDT],
7+
[FANTOM_TOKENS.gDAI, FANTOM_TOKENS.DAI],
8+
[FANTOM_TOKENS.gUSDC, FANTOM_TOKENS.USDC],
9+
[FANTOM_TOKENS.gETH, FANTOM_TOKENS.WETH],
10+
[FANTOM_TOKENS.gWBTC, FANTOM_TOKENS.WBTC],
11+
[FANTOM_TOKENS.gCRV, FANTOM_TOKENS.WCRV],
12+
[FANTOM_TOKENS.gMIM, FANTOM_TOKENS.MIM],
13+
]);
14+
15+
export function getGeistInfoForPair(
16+
takerToken: string,
17+
makerToken: string,
18+
): GeistInfo | undefined {
19+
let gToken;
20+
let underlyingToken;
21+
if (gTokenToUnderlyingToken.get(takerToken) === makerToken) {
22+
gToken = takerToken;
23+
underlyingToken = makerToken;
24+
} else if (gTokenToUnderlyingToken.get(makerToken) === takerToken) {
25+
gToken = makerToken;
26+
underlyingToken = takerToken;
27+
} else {
28+
return undefined;
29+
}
30+
31+
return {
32+
lendingPool: GEIST_FANTOM_POOLS.lendingPool,
33+
gToken,
34+
underlyingToken,
35+
};
36+
}

packages/asset-swapper/src/utils/market_operation_utils/orders.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ERC20BridgeSource,
1919
FillData,
2020
FinalUniswapV3FillData,
21+
GeistFillData,
2122
GenericRouterFillData,
2223
KyberDmmFillData,
2324
KyberFillData,
@@ -202,6 +203,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
202203
return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'AaveV2');
203204
case ERC20BridgeSource.Compound:
204205
return encodeBridgeSourceId(BridgeProtocol.Compound, 'Compound');
206+
case ERC20BridgeSource.Geist:
207+
return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'Geist');
205208
default:
206209
throw new Error(AggregationError.NoBridgeForSource);
207210
}
@@ -356,6 +359,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
356359
const compoundFillData = (order as OptimizedMarketBridgeOrder<CompoundFillData>).fillData;
357360
bridgeData = encoder.encode([compoundFillData.cToken]);
358361
break;
362+
case ERC20BridgeSource.Geist:
363+
const geistFillData = (order as OptimizedMarketBridgeOrder<GeistFillData>).fillData;
364+
bridgeData = encoder.encode([geistFillData.lendingPool, geistFillData.gToken]);
365+
break;
359366

360367
default:
361368
throw new Error(AggregationError.NoBridgeForSource);
@@ -525,6 +532,7 @@ export const BRIDGE_ENCODERS: {
525532
[ERC20BridgeSource.Lido]: AbiEncoder.create('(address)'),
526533
[ERC20BridgeSource.AaveV2]: AbiEncoder.create('(address,address)'),
527534
[ERC20BridgeSource.Compound]: AbiEncoder.create('(address)'),
535+
[ERC20BridgeSource.Geist]: AbiEncoder.create('(address,address)'),
528536
};
529537

530538
function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] {

packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { BigNumber, logUtils } from '@0x/utils';
44
import * as _ from 'lodash';
55

66
import { AaveV2Sampler } from '../../noop_samplers/AaveV2Sampler';
7+
import { GeistSampler } from '../../noop_samplers/GeistSampler';
78
import { SamplerCallResult, SignedNativeOrder } from '../../types';
89
import { ERC20BridgeSamplerContract } from '../../wrappers';
910

@@ -46,6 +47,7 @@ import {
4647
UNISWAPV3_CONFIG_BY_CHAIN_ID,
4748
ZERO_AMOUNT,
4849
} from './constants';
50+
import { getGeistInfoForPair } from './geist_utils';
4951
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
5052
import { getIntermediateTokens } from './multihop_utils';
5153
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
@@ -66,6 +68,8 @@ import {
6668
DexSample,
6769
DODOFillData,
6870
ERC20BridgeSource,
71+
GeistFillData,
72+
GeistInfo,
6973
GenericRouterFillData,
7074
HopInfo,
7175
KyberDmmFillData,
@@ -1151,6 +1155,34 @@ export class SamplerOperations {
11511155
});
11521156
}
11531157

1158+
// tslint:disable-next-line:prefer-function-over-method
1159+
public getGeistSellQuotes(
1160+
geistInfo: GeistInfo,
1161+
makerToken: string,
1162+
takerToken: string,
1163+
takerFillAmounts: BigNumber[],
1164+
): SourceQuoteOperation<GeistFillData> {
1165+
return new SamplerNoOperation({
1166+
source: ERC20BridgeSource.Geist,
1167+
fillData: { ...geistInfo, takerToken },
1168+
callback: () => GeistSampler.sampleSellsFromGeist(geistInfo, takerToken, makerToken, takerFillAmounts),
1169+
});
1170+
}
1171+
1172+
// tslint:disable-next-line:prefer-function-over-method
1173+
public getGeistBuyQuotes(
1174+
geistInfo: GeistInfo,
1175+
makerToken: string,
1176+
takerToken: string,
1177+
makerFillAmounts: BigNumber[],
1178+
): SourceQuoteOperation<GeistFillData> {
1179+
return new SamplerNoOperation({
1180+
source: ERC20BridgeSource.Geist,
1181+
fillData: { ...geistInfo, takerToken },
1182+
callback: () => GeistSampler.sampleBuysFromGeist(geistInfo, takerToken, makerToken, makerFillAmounts),
1183+
});
1184+
}
1185+
11541186
public getCompoundSellQuotes(
11551187
cToken: string,
11561188
makerToken: string,
@@ -1548,6 +1580,13 @@ export class SamplerOperations {
15481580
};
15491581
return this.getAaveV2SellQuotes(info, makerToken, takerToken, takerFillAmounts);
15501582
}
1583+
case ERC20BridgeSource.Geist: {
1584+
const info: GeistInfo | undefined = getGeistInfoForPair(takerToken, makerToken);
1585+
if (!info) {
1586+
return [];
1587+
}
1588+
return this.getGeistSellQuotes(info, makerToken, takerToken, takerFillAmounts);
1589+
}
15511590
case ERC20BridgeSource.Compound: {
15521591
if (!this.compoundCTokenCache) {
15531592
return [];
@@ -1578,7 +1617,7 @@ export class SamplerOperations {
15781617
takerToken: string,
15791618
makerFillAmounts: BigNumber[],
15801619
): SourceQuoteOperation[] {
1581-
// Find the adjacent tokens in the provided tooken adjacency graph,
1620+
// Find the adjacent tokens in the provided token adjacency graph,
15821621
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
15831622
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
15841623
const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources);
@@ -1849,6 +1888,13 @@ export class SamplerOperations {
18491888
};
18501889
return this.getAaveV2BuyQuotes(info, makerToken, takerToken, makerFillAmounts);
18511890
}
1891+
case ERC20BridgeSource.Geist: {
1892+
const info: GeistInfo | undefined = getGeistInfoForPair(takerToken, makerToken);
1893+
if (!info) {
1894+
return [];
1895+
}
1896+
return this.getGeistBuyQuotes(info, makerToken, takerToken, makerFillAmounts);
1897+
}
18521898
case ERC20BridgeSource.Compound: {
18531899
if (!this.compoundCTokenCache) {
18541900
return [];

packages/asset-swapper/src/utils/market_operation_utils/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export enum ERC20BridgeSource {
102102
SpookySwap = 'SpookySwap',
103103
Beethovenx = 'Beethovenx',
104104
MorpheusSwap = 'MorpheusSwap',
105+
Geist = 'Geist',
105106
}
106107
export type SourcesWithPoolsCache =
107108
| ERC20BridgeSource.Balancer
@@ -181,6 +182,12 @@ export interface AaveV2Info {
181182
underlyingToken: string;
182183
}
183184

185+
export interface GeistInfo {
186+
lendingPool: string;
187+
gToken: string;
188+
underlyingToken: string;
189+
}
190+
184191
// Internal `fillData` field for `Fill` objects.
185192
export interface FillData {}
186193

@@ -301,6 +308,13 @@ export interface CompoundFillData extends FillData {
301308
makerToken: string;
302309
}
303310

311+
export interface GeistFillData extends FillData {
312+
lendingPool: string;
313+
gToken: string;
314+
underlyingToken: string;
315+
takerToken: string;
316+
}
317+
304318
/**
305319
* Represents a node on a fill path.
306320
*/

packages/contract-addresses/CHANGELOG.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
[
2+
3+
{
4+
"version": "6.12.0",
5+
"changes": [
6+
{
7+
"note": "Update fantom fillQuoteTransformer addresses",
8+
"pr": 398
9+
}
10+
]
11+
},
212
{
313
"version": "6.11.0",
414
"changes": [

packages/contract-addresses/addresses.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@
415415
"wethTransformer": "0x9b6aa8f26a92108e7d1f66373d757bb955112703",
416416
"payTakerTransformer": "0x32df54951d33d7460e15fa59b1fcc262183ce4c2",
417417
"affiliateFeeTransformer": "0x67efa679a4b56c38713d478e649c88247f4f8e88",
418-
"fillQuoteTransformer": "0x71de60a1b160094a3f6c7e1b883ff9337d639131",
418+
"fillQuoteTransformer": "0x641efe8a57ad39353fe22f77d211ef6b17b0590b",
419419
"positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600"
420420
}
421421
},

0 commit comments

Comments
 (0)