Skip to content

Commit

Permalink
Euler client (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Sep 27, 2022
1 parent 87d962f commit 3226a7b
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aztec/bridge-clients",
"version": "0.1.59",
"version": "0.1.60",
"description": "This repo contains the solidity files and typescript helper class for all of the Aztec Connect Bridge Contracts",
"repository": "git@github.com:AztecProtocol/aztec-connect-bridges.git",
"license": "Apache-2.0",
Expand Down
15 changes: 15 additions & 0 deletions src/client/erc4626/erc4626-bridge-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,19 @@ describe("ERC4626 bridge data", () => {
)[0];
expect(expectedOutput).toBe(111111n);
});

it("should correctly get asset", async () => {
// Setup mocks
erc4626Contract = {
...erc4626Contract,
asset: jest.fn().mockResolvedValue(mplAsset.erc20Address.toString()),
};
IERC4626__factory.connect = () => erc4626Contract as any;

const erc4626BridgeData = ERC4626BridgeData.create({} as any);

// Test the code using mocked controller
const asset = await erc4626BridgeData.getAsset(xmplAsset.erc20Address);
expect(asset.toString()).toBe(mplAsset.erc20Address.toString());
});
});
18 changes: 17 additions & 1 deletion src/client/erc4626/erc4626-bridge-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { AuxDataConfig, AztecAsset, BridgeDataFieldGetters, SolidityType } from

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

private constructor(private ethersProvider: Web3Provider) {}
protected constructor(protected ethersProvider: Web3Provider) {}

static create(provider: EthereumProvider) {
const ethersProvider = createWeb3Provider(provider);
Expand Down Expand Up @@ -81,4 +82,19 @@ export class ERC4626BridgeData implements BridgeDataFieldGetters {
throw "Invalid auxData";
}
}

/**
* @notice Gets asset for a given share
* @param share Address of the share/vault
* @return Address of the underlying asset
*/
async getAsset(share: EthAddress): Promise<EthAddress> {
let asset = this.shareToAssetMap.get(share);
if (asset === undefined) {
const vault = IERC4626__factory.connect(share.toString(), this.ethersProvider);
asset = EthAddress.fromString(await vault.asset());
this.shareToAssetMap.set(share, asset);
}
return asset;
}
}
63 changes: 63 additions & 0 deletions src/client/euler/euler-bridge-data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { EthAddress } from "@aztec/barretenberg/address";
import { IERC4626, IERC4626__factory } from "../../../typechain-types";
import { AztecAsset, AztecAssetType } from "../bridge-data";
import { EulerBridgeData } from "./euler-bridge-data";

jest.mock("../aztec/provider", () => ({
createWeb3Provider: jest.fn(),
}));

type Mockify<T> = {
[P in keyof T]: jest.Mock | any;
};

describe("Euler bridge data", () => {
let erc4626Contract: Mockify<IERC4626>;

let ethAsset: AztecAsset;
let weDaiAsset: AztecAsset;
let daiAsset: AztecAsset;
let emptyAsset: AztecAsset;

beforeAll(() => {
ethAsset = {
id: 0,
assetType: AztecAssetType.ETH,
erc20Address: EthAddress.ZERO,
};
weDaiAsset = {
id: 7,
assetType: AztecAssetType.ERC20,
erc20Address: EthAddress.fromString("0x4169Df1B7820702f566cc10938DA51F6F597d264"),
};
daiAsset = {
id: 1,
assetType: AztecAssetType.ERC20,
erc20Address: EthAddress.fromString("0x6b175474e89094c44da98b954eedeac495271d0f"),
};
emptyAsset = {
id: 0,
assetType: AztecAssetType.NOT_USED,
erc20Address: EthAddress.ZERO,
};
});

it("should correctly fetch APR", async () => {
erc4626Contract = {
...erc4626Contract,
asset: jest.fn().mockResolvedValue(daiAsset.erc20Address.toString()),
};
IERC4626__factory.connect = () => erc4626Contract as any;

const eulerBridgeData = EulerBridgeData.create({} as any);
const apr = await eulerBridgeData.getAPR(weDaiAsset);
expect(apr).toBeGreaterThan(0);
});

it("should correctly fetch market size", async () => {
const eulerBridgeData = EulerBridgeData.create({} as any);
const assetValue = (await eulerBridgeData.getMarketSize(daiAsset, emptyAsset, emptyAsset, emptyAsset, 0))[0];
expect(assetValue.assetId).toBe(daiAsset.id);
expect(assetValue.value).toBeGreaterThan(0);
});
});
85 changes: 85 additions & 0 deletions src/client/euler/euler-bridge-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { AssetValue } from "@aztec/barretenberg/asset";
import { EthereumProvider } from "@aztec/barretenberg/blockchain";
import { Web3Provider } from "@ethersproject/providers";
import "isomorphic-fetch";
import { createWeb3Provider } from "../aztec/provider";
import { AztecAsset } from "../bridge-data";

import { ERC4626BridgeData } from "../erc4626/erc4626-bridge-data";

export class EulerBridgeData extends ERC4626BridgeData {
protected constructor(ethersProvider: Web3Provider) {
super(ethersProvider);
}

static create(provider: EthereumProvider) {
const ethersProvider = createWeb3Provider(provider);
return new EulerBridgeData(ethersProvider);
}

async getAPR(yieldAsset: AztecAsset): Promise<number> {
const underlyingAddress = await this.getAsset(yieldAsset.erc20Address);
const result = await (
await fetch("https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
query($id: String!) {
asset(id: $id) {
supplyAPY
}
}
`,
variables: {
id: underlyingAddress.toString().toLowerCase(),
},
}),
})
).json();

return result.data.asset.supplyAPY / 10 ** 25;
}

/**
* @notice Gets market size which in this case means the amount of underlying asset deposited to Euler
* @param inputAssetA - The underlying asset
* @param inputAssetB - ignored
* @param outputAssetA - ignored
* @param outputAssetB - ignored
* @param auxData - ignored
* @return The amount of the underlying asset deposited to Euler
* @dev the returned value is displayed as totalSupply in Euler's UI
*/
async getMarketSize(
inputAssetA: AztecAsset,
inputAssetB: AztecAsset,
outputAssetA: AztecAsset,
outputAssetB: AztecAsset,
auxData: number,
): Promise<AssetValue[]> {
const result = await (
await fetch("https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
query($id: String!) {
asset(id: $id) {
totalBalances
}
}
`,
variables: {
id: inputAssetA.erc20Address.toString().toLowerCase(),
},
}),
})
).json();
return [{ assetId: inputAssetA.id, value: BigInt(result.data.asset.totalBalances) }];
}
}

0 comments on commit 3226a7b

Please sign in to comment.