Skip to content

Commit

Permalink
Add data provider (#231)
Browse files Browse the repository at this point in the history
* add data provider

* reduce solidity version

* fix path in data-provider

* Add fetches for all and natspec + tests

* update devnet address + extend aggregate with stats

* update yearn token gas

* remove `createSelectFork` cheatcode

* feat: add subsidy helper function in provider

* fix: top-up funding of yearn subsidy to ensure subsidy accrues

* fix: add `getAccumulatedSubsidyAmount` to wrapper
  • Loading branch information
LHerskind authored Sep 12, 2022
1 parent 94bd459 commit 17b0631
Show file tree
Hide file tree
Showing 8 changed files with 575 additions and 6 deletions.
220 changes: 220 additions & 0 deletions src/aztec/DataProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;
import {AztecTypes} from "./libraries/AztecTypes.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IRollupProcessor} from "./interfaces/IRollupProcessor.sol";
import {BridgeBase} from "../bridges/base/BridgeBase.sol";
import {ISubsidy} from "./interfaces/ISubsidy.sol";

/**
* @notice Helper used for mapping assets and bridges to more meaningful naming
* @author Aztec Team
*/
contract DataProvider is Ownable {
struct BridgeData {
address bridgeAddress;
uint256 bridgeAddressId;
string label;
}

struct AssetData {
address assetAddress;
uint256 assetId;
string label;
}

struct Bridges {
mapping(uint256 => BridgeData) data;
mapping(bytes32 => uint256) tagToId;
}

struct Assets {
mapping(uint256 => AssetData) data;
mapping(bytes32 => uint256) tagToId;
}

uint256 private constant INPUT_ASSET_ID_A_SHIFT = 32;
uint256 private constant INPUT_ASSET_ID_B_SHIFT = 62;
uint256 private constant OUTPUT_ASSET_ID_A_SHIFT = 92;
uint256 private constant OUTPUT_ASSET_ID_B_SHIFT = 122;
uint256 private constant BITCONFIG_SHIFT = 152;
uint256 private constant AUX_DATA_SHIFT = 184;
uint256 private constant VIRTUAL_ASSET_ID_FLAG_SHIFT = 29;
uint256 private constant VIRTUAL_ASSET_ID_FLAG = 0x20000000; // 2 ** 29
uint256 private constant MASK_THIRTY_TWO_BITS = 0xffffffff;
uint256 private constant MASK_THIRTY_BITS = 0x3fffffff;
uint256 private constant MASK_SIXTY_FOUR_BITS = 0xffffffffffffffff;

ISubsidy public constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA);
IRollupProcessor public immutable ROLLUP_PROCESSOR;
Bridges internal bridges;
Assets internal assets;

constructor(address _rollupProcessor) {
ROLLUP_PROCESSOR = IRollupProcessor(_rollupProcessor);
}

/**
* @notice Adds a bridge with a specific tag
* @dev Only callable by the owner
* @param _bridgeAddressId The bridge address id for the bridge to list
* @param _tag The tag to list with the bridge
*/
function addBridge(uint256 _bridgeAddressId, string memory _tag) public onlyOwner {
address bridgeAddress = ROLLUP_PROCESSOR.getSupportedBridge(_bridgeAddressId);
bytes32 digest = keccak256(abi.encode(_tag));
bridges.tagToId[digest] = _bridgeAddressId;
bridges.data[_bridgeAddressId] = BridgeData({
bridgeAddress: bridgeAddress,
bridgeAddressId: _bridgeAddressId,
label: _tag
});
}

/**
* @notice Adds an asset with a specific tag
* @dev Only callable by the owner
* @param _assetId The asset id of the asset to list
* @param _tag The tag to list with the asset
*/
function addAsset(uint256 _assetId, string memory _tag) public onlyOwner {
address assetAddress = ROLLUP_PROCESSOR.getSupportedAsset(_assetId);
bytes32 digest = keccak256(abi.encode(_tag));
assets.tagToId[digest] = _assetId;
assets.data[_assetId] = AssetData({assetAddress: assetAddress, assetId: _assetId, label: _tag});
}

/**
* @notice Fetch the `BridgeData` related to a specific bridgeAddressId
* @param _bridgeAddressId The bridge address id of the bridge to fetch
* @return The BridgeData data structure for the given bridge
*/
function getBridge(uint256 _bridgeAddressId) public view returns (BridgeData memory) {
return bridges.data[_bridgeAddressId];
}

/**
* @notice Fetch the `BridgeData` related to a specific tag
* @param _tag The tag of the bridge to fetch
* @return The BridgeData data structure for the given bridge
*/
function getBridge(string memory _tag) public view returns (BridgeData memory) {
return bridges.data[bridges.tagToId[keccak256(abi.encode(_tag))]];
}

/**
* @notice Fetch the `AssetData` related to a specific assetId
* @param _assetId The asset id of the asset to fetch
* @return The AssetData data structure for the given asset
*/
function getAsset(uint256 _assetId) public view returns (AssetData memory) {
return assets.data[_assetId];
}

/**
* @notice Fetch the `AssetData` related to a specific tag
* @param _tag The tag of the asset to fetch
* @return The AssetData data structure for the given asset
*/
function getAsset(string memory _tag) public view returns (AssetData memory) {
return assets.data[assets.tagToId[keccak256(abi.encode(_tag))]];
}

/**
* @notice Fetch `AssetData` for all supported assets
* @return A list of AssetData data structures, one for every asset
*/
function getAssets() public view returns (AssetData[] memory) {
uint256 assetCount = ROLLUP_PROCESSOR.getSupportedAssetsLength();
AssetData[] memory assetDatas = new AssetData[](assetCount);
for (uint256 i = 0; i < assetCount; i++) {
assetDatas[i] = getAsset(i);
}
return assetDatas;
}

/**
* @notice Fetch `BridgeData` for all supported bridges
* @return A list of BridgeData data structures, one for every bridge
*/
function getBridges() public view returns (BridgeData[] memory) {
uint256 bridgeCount = ROLLUP_PROCESSOR.getSupportedBridgesLength();
BridgeData[] memory bridgeDatas = new BridgeData[](bridgeCount);
for (uint256 i = 1; i <= bridgeCount; i++) {
bridgeDatas[i - 1] = getBridge(i);
}
return bridgeDatas;
}

/**
* @notice Fetches the subsidy that can be claimed by the specific call, if it is the next performed.
* @param _bridgeCallData The bridge call data for a specific bridge interaction
* @return The amount of eth claimed at the current gas prices
*/
function getAccumulatedSubsidyAmount(uint256 _bridgeCallData) public view returns (uint256) {
uint256 bridgeAddressId = _bridgeCallData & MASK_THIRTY_TWO_BITS;
address bridgeAddress = ROLLUP_PROCESSOR.getSupportedBridge(bridgeAddressId);

uint256 inputAId = (_bridgeCallData >> INPUT_ASSET_ID_A_SHIFT) & MASK_THIRTY_BITS;
uint256 inputBId = (_bridgeCallData >> INPUT_ASSET_ID_B_SHIFT) & MASK_THIRTY_BITS;
uint256 outputAId = (_bridgeCallData >> OUTPUT_ASSET_ID_A_SHIFT) & MASK_THIRTY_BITS;
uint256 outputBId = (_bridgeCallData >> OUTPUT_ASSET_ID_B_SHIFT) & MASK_THIRTY_BITS;
uint256 bitconfig = (_bridgeCallData >> BITCONFIG_SHIFT) & MASK_THIRTY_TWO_BITS;
uint256 auxData = (_bridgeCallData >> AUX_DATA_SHIFT) & MASK_SIXTY_FOUR_BITS;

AztecTypes.AztecAsset memory inputA = _aztecAsset(inputAId);
AztecTypes.AztecAsset memory inputB;
if (bitconfig & 1 == 1) {
inputB = _aztecAsset(inputBId);
}

AztecTypes.AztecAsset memory outputA = _aztecAsset(outputAId);
AztecTypes.AztecAsset memory outputB;

if (bitconfig & 2 == 2) {
outputB = _aztecAsset(outputBId);
}

(bool success, bytes memory returnData) = bridgeAddress.staticcall(
abi.encodeWithSelector(
BridgeBase.computeCriteria.selector,
inputA,
inputB,
outputA,
outputB,
uint64(auxData)
)
);

if (!success) {
return 0;
}

uint256 criteria = abi.decode(returnData, (uint256));

return SUBSIDY.getAccumulatedSubsidyAmount(bridgeAddress, criteria);
}

function _aztecAsset(uint256 _assetId) internal view returns (AztecTypes.AztecAsset memory) {
if (_assetId >= VIRTUAL_ASSET_ID_FLAG) {
return
AztecTypes.AztecAsset({
id: _assetId - VIRTUAL_ASSET_ID_FLAG,
erc20Address: address(0),
assetType: AztecTypes.AztecAssetType.VIRTUAL
});
}

if (_assetId > 0) {
return
AztecTypes.AztecAsset({
id: _assetId,
erc20Address: ROLLUP_PROCESSOR.getSupportedAsset(_assetId),
assetType: AztecTypes.AztecAssetType.ERC20
});
}

return AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH});
}
}
4 changes: 4 additions & 0 deletions src/aztec/interfaces/IRollupProcessor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,8 @@ interface IRollupProcessor {
function getSupportedAsset(uint256 _assetId) external view returns (address);

function getEscapeHatchStatus() external view returns (bool, uint256);

function assetGasLimits(uint256 _bridgeAddressId) external view returns (uint256);

function bridgeGasLimits(uint256 _bridgeAddressId) external view returns (uint256);
}
100 changes: 100 additions & 0 deletions src/client/aztec/data-provider/DataProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { EthAddress } from "@aztec/barretenberg/address";
import { EthereumProvider } from "@aztec/barretenberg/blockchain";
import { DataProvider__factory } from "../../../../typechain-types";
import { DataProvider } from "../../../../typechain-types";
import { createWeb3Provider } from "../provider";

export interface AssetData {
assetAddress: EthAddress;
assetId: number;
label: string;
}

export interface BridgeData {
bridgeAddress: EthAddress;
bridgeAddressId: number;
label: string;
}

export class DataProviderWrapper {
private constructor(private dataProvider: DataProvider) {}

static create(provider: EthereumProvider, dataProviderAddress: EthAddress) {
const ethersProvider = createWeb3Provider(provider);
return new DataProviderWrapper(DataProvider__factory.connect(dataProviderAddress.toString(), ethersProvider));
}

async getBridgeByName(name: string): Promise<BridgeData> {
const bd = await this.dataProvider["getBridge(string)"](name);
return {
bridgeAddress: EthAddress.fromString(bd.bridgeAddress),
bridgeAddressId: bd.bridgeAddressId.toNumber(),
label: bd.label,
};
}

async getBridgeById(bridgeAddressId: number): Promise<BridgeData> {
const bd = await this.dataProvider["getBridge(uint256)"](bridgeAddressId);
return {
bridgeAddress: EthAddress.fromString(bd.bridgeAddress),
bridgeAddressId: bd.bridgeAddressId.toNumber(),
label: bd.label,
};
}

async getAssetByName(name: string): Promise<AssetData> {
const ad = await this.dataProvider["getAsset(string)"](name);
return {
assetAddress: EthAddress.fromString(ad.assetAddress),
assetId: ad.assetId.toNumber(),
label: ad.label,
};
}

async getAssetById(assetId: number): Promise<AssetData> {
const ad = await this.dataProvider["getAsset(uint256)"](assetId);
return {
assetAddress: EthAddress.fromString(ad.assetAddress),
assetId: ad.assetId.toNumber(),
label: ad.label,
};
}

async getAssets(): Promise<{ [key: string]: AssetData }> {
const assetDatas = await this.dataProvider.getAssets();
const dict: { [key: string]: AssetData } = {};
assetDatas.forEach(asset => {
if (asset.label != "") {
dict[asset.label] = {
assetAddress: EthAddress.fromString(asset.assetAddress),
assetId: asset.assetId.toNumber(),
label: asset.label,
};
}
});
return dict;
}

async getBridges(): Promise<{ [key: string]: BridgeData }> {
const bridgeDatas = await this.dataProvider.getBridges();
const dict: { [key: string]: BridgeData } = {};
bridgeDatas.forEach(bridge => {
if (bridge.label != "") {
dict[bridge.label] = {
bridgeAddress: EthAddress.fromString(bridge.bridgeAddress),
bridgeAddressId: bridge.bridgeAddressId.toNumber(),
label: bridge.label,
};
}
});
return dict;
}

async getRollupProvider(): Promise<EthAddress> {
return EthAddress.fromString(await this.dataProvider.ROLLUP_PROCESSOR());
}

async getAccumulatedSubsidyAmount(bridgeCallData: bigint): Promise<bigint> {
return (await this.dataProvider.getAccumulatedSubsidyAmount(bridgeCallData)).toBigInt();
}
}
34 changes: 32 additions & 2 deletions src/deployment/AggregateDeployment.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;

import {Test} from "forge-std/Test.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import {BaseDeployment} from "./base/BaseDeployment.s.sol";
import {IRollupProcessor} from "../aztec/interfaces/IRollupProcessor.sol";

import {CompoundDeployment} from "./compound/CompoundDeployment.s.sol";
import {CurveDeployment} from "./curve/CurveDeployment.s.sol";
Expand All @@ -15,7 +19,7 @@ import {YearnDeployment} from "./yearn/YearnDeployment.s.sol";
/**
* A helper script that allow easy deployment of multiple bridges
*/
contract AggregateDeployment is Test {
contract AggregateDeployment is BaseDeployment {
function deployAndListAll() public {
emit log("--- Curve ---");
{
Expand All @@ -31,4 +35,30 @@ contract AggregateDeployment is Test {
yDeploy.deployAndList();
}
}

function readStats() public {
IRollupProcessor rp = IRollupProcessor(ROLLUP_PROCESSOR);

uint256 assetCount = assetLength();
emit log_named_uint("Assets added ", assetCount);
for (uint256 i = 0; i < assetCount; i++) {
string memory symbol = i > 0 ? IERC20Metadata(rp.getSupportedAsset(i)).symbol() : "Eth";
uint256 gas = i > 0 ? rp.assetGasLimits(i) : 30000;
emit log_named_string(
string(abi.encodePacked(" Asset ", Strings.toString(i))),
string(abi.encodePacked(symbol, ", ", Strings.toString(gas)))
);
}

uint256 bridgeCount = bridgesLength();
emit log_named_uint("Bridges added", bridgeCount);
for (uint256 i = 1; i <= bridgeCount; i++) {
address bridge = rp.getSupportedBridge(i);
uint256 gas = rp.bridgeGasLimits(i);
emit log_named_string(
string(abi.encodePacked(" Bridge ", Strings.toString(i))),
string(abi.encodePacked(Strings.toHexString(bridge), ", ", Strings.toString(gas)))
);
}
}
}
2 changes: 0 additions & 2 deletions src/deployment/base/BaseDeployment.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,8 @@ abstract contract BaseDeployment is Test {
NETWORK = Network.MAINNET;
} else if (envNetworkHash == keccak256(abi.encodePacked("devnet"))) {
NETWORK = Network.DEVNET;
vm.createSelectFork("https://mainnet-fork.aztec.network:8545");
} else if (envNetworkHash == keccak256(abi.encodePacked("testnet"))) {
NETWORK = Network.TESTNET;
vm.createSelectFork("https://mainnet-fork.aztec.network:8545");
}

if (envMode) {
Expand Down
Loading

0 comments on commit 17b0631

Please sign in to comment.