Skip to content

Commit 3226a7b

Browse files
authored
Euler client (#243)
1 parent 87d962f commit 3226a7b

File tree

5 files changed

+181
-2
lines changed

5 files changed

+181
-2
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aztec/bridge-clients",
3-
"version": "0.1.59",
3+
"version": "0.1.60",
44
"description": "This repo contains the solidity files and typescript helper class for all of the Aztec Connect Bridge Contracts",
55
"repository": "[email protected]:AztecProtocol/aztec-connect-bridges.git",
66
"license": "Apache-2.0",

src/client/erc4626/erc4626-bridge-data.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,19 @@ describe("ERC4626 bridge data", () => {
106106
)[0];
107107
expect(expectedOutput).toBe(111111n);
108108
});
109+
110+
it("should correctly get asset", async () => {
111+
// Setup mocks
112+
erc4626Contract = {
113+
...erc4626Contract,
114+
asset: jest.fn().mockResolvedValue(mplAsset.erc20Address.toString()),
115+
};
116+
IERC4626__factory.connect = () => erc4626Contract as any;
117+
118+
const erc4626BridgeData = ERC4626BridgeData.create({} as any);
119+
120+
// Test the code using mocked controller
121+
const asset = await erc4626BridgeData.getAsset(xmplAsset.erc20Address);
122+
expect(asset.toString()).toBe(mplAsset.erc20Address.toString());
123+
});
109124
});

src/client/erc4626/erc4626-bridge-data.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { AuxDataConfig, AztecAsset, BridgeDataFieldGetters, SolidityType } from
77

88
export class ERC4626BridgeData implements BridgeDataFieldGetters {
99
readonly WETH = EthAddress.fromString("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
10+
shareToAssetMap = new Map<EthAddress, EthAddress>();
1011

11-
private constructor(private ethersProvider: Web3Provider) {}
12+
protected constructor(protected ethersProvider: Web3Provider) {}
1213

1314
static create(provider: EthereumProvider) {
1415
const ethersProvider = createWeb3Provider(provider);
@@ -81,4 +82,19 @@ export class ERC4626BridgeData implements BridgeDataFieldGetters {
8182
throw "Invalid auxData";
8283
}
8384
}
85+
86+
/**
87+
* @notice Gets asset for a given share
88+
* @param share Address of the share/vault
89+
* @return Address of the underlying asset
90+
*/
91+
async getAsset(share: EthAddress): Promise<EthAddress> {
92+
let asset = this.shareToAssetMap.get(share);
93+
if (asset === undefined) {
94+
const vault = IERC4626__factory.connect(share.toString(), this.ethersProvider);
95+
asset = EthAddress.fromString(await vault.asset());
96+
this.shareToAssetMap.set(share, asset);
97+
}
98+
return asset;
99+
}
84100
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { EthAddress } from "@aztec/barretenberg/address";
2+
import { IERC4626, IERC4626__factory } from "../../../typechain-types";
3+
import { AztecAsset, AztecAssetType } from "../bridge-data";
4+
import { EulerBridgeData } from "./euler-bridge-data";
5+
6+
jest.mock("../aztec/provider", () => ({
7+
createWeb3Provider: jest.fn(),
8+
}));
9+
10+
type Mockify<T> = {
11+
[P in keyof T]: jest.Mock | any;
12+
};
13+
14+
describe("Euler bridge data", () => {
15+
let erc4626Contract: Mockify<IERC4626>;
16+
17+
let ethAsset: AztecAsset;
18+
let weDaiAsset: AztecAsset;
19+
let daiAsset: AztecAsset;
20+
let emptyAsset: AztecAsset;
21+
22+
beforeAll(() => {
23+
ethAsset = {
24+
id: 0,
25+
assetType: AztecAssetType.ETH,
26+
erc20Address: EthAddress.ZERO,
27+
};
28+
weDaiAsset = {
29+
id: 7,
30+
assetType: AztecAssetType.ERC20,
31+
erc20Address: EthAddress.fromString("0x4169Df1B7820702f566cc10938DA51F6F597d264"),
32+
};
33+
daiAsset = {
34+
id: 1,
35+
assetType: AztecAssetType.ERC20,
36+
erc20Address: EthAddress.fromString("0x6b175474e89094c44da98b954eedeac495271d0f"),
37+
};
38+
emptyAsset = {
39+
id: 0,
40+
assetType: AztecAssetType.NOT_USED,
41+
erc20Address: EthAddress.ZERO,
42+
};
43+
});
44+
45+
it("should correctly fetch APR", async () => {
46+
erc4626Contract = {
47+
...erc4626Contract,
48+
asset: jest.fn().mockResolvedValue(daiAsset.erc20Address.toString()),
49+
};
50+
IERC4626__factory.connect = () => erc4626Contract as any;
51+
52+
const eulerBridgeData = EulerBridgeData.create({} as any);
53+
const apr = await eulerBridgeData.getAPR(weDaiAsset);
54+
expect(apr).toBeGreaterThan(0);
55+
});
56+
57+
it("should correctly fetch market size", async () => {
58+
const eulerBridgeData = EulerBridgeData.create({} as any);
59+
const assetValue = (await eulerBridgeData.getMarketSize(daiAsset, emptyAsset, emptyAsset, emptyAsset, 0))[0];
60+
expect(assetValue.assetId).toBe(daiAsset.id);
61+
expect(assetValue.value).toBeGreaterThan(0);
62+
});
63+
});

src/client/euler/euler-bridge-data.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { AssetValue } from "@aztec/barretenberg/asset";
2+
import { EthereumProvider } from "@aztec/barretenberg/blockchain";
3+
import { Web3Provider } from "@ethersproject/providers";
4+
import "isomorphic-fetch";
5+
import { createWeb3Provider } from "../aztec/provider";
6+
import { AztecAsset } from "../bridge-data";
7+
8+
import { ERC4626BridgeData } from "../erc4626/erc4626-bridge-data";
9+
10+
export class EulerBridgeData extends ERC4626BridgeData {
11+
protected constructor(ethersProvider: Web3Provider) {
12+
super(ethersProvider);
13+
}
14+
15+
static create(provider: EthereumProvider) {
16+
const ethersProvider = createWeb3Provider(provider);
17+
return new EulerBridgeData(ethersProvider);
18+
}
19+
20+
async getAPR(yieldAsset: AztecAsset): Promise<number> {
21+
const underlyingAddress = await this.getAsset(yieldAsset.erc20Address);
22+
const result = await (
23+
await fetch("https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet", {
24+
method: "POST",
25+
headers: {
26+
"Content-Type": "application/json",
27+
},
28+
body: JSON.stringify({
29+
query: `
30+
query($id: String!) {
31+
asset(id: $id) {
32+
supplyAPY
33+
}
34+
}
35+
`,
36+
variables: {
37+
id: underlyingAddress.toString().toLowerCase(),
38+
},
39+
}),
40+
})
41+
).json();
42+
43+
return result.data.asset.supplyAPY / 10 ** 25;
44+
}
45+
46+
/**
47+
* @notice Gets market size which in this case means the amount of underlying asset deposited to Euler
48+
* @param inputAssetA - The underlying asset
49+
* @param inputAssetB - ignored
50+
* @param outputAssetA - ignored
51+
* @param outputAssetB - ignored
52+
* @param auxData - ignored
53+
* @return The amount of the underlying asset deposited to Euler
54+
* @dev the returned value is displayed as totalSupply in Euler's UI
55+
*/
56+
async getMarketSize(
57+
inputAssetA: AztecAsset,
58+
inputAssetB: AztecAsset,
59+
outputAssetA: AztecAsset,
60+
outputAssetB: AztecAsset,
61+
auxData: number,
62+
): Promise<AssetValue[]> {
63+
const result = await (
64+
await fetch("https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet", {
65+
method: "POST",
66+
headers: {
67+
"Content-Type": "application/json",
68+
},
69+
body: JSON.stringify({
70+
query: `
71+
query($id: String!) {
72+
asset(id: $id) {
73+
totalBalances
74+
}
75+
}
76+
`,
77+
variables: {
78+
id: inputAssetA.erc20Address.toString().toLowerCase(),
79+
},
80+
}),
81+
})
82+
).json();
83+
return [{ assetId: inputAssetA.id, value: BigInt(result.data.asset.totalBalances) }];
84+
}
85+
}

0 commit comments

Comments
 (0)