Chainlink stop-limit orders (#2473)
* Contracts for Chainlink stop-limit orders * Tests and asset data utils * Update contracts-integrations changelog * Address comments * Remove priceFreshness parameter * Remove LibSafeMath * fix typo * Add ChainlinkStopLimit addresses to @0x/contract-addresses
This commit is contained in:
parent
dfd9443f74
commit
f471c79b59
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.4.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added ChainlinkStopLimit contract and tests",
|
||||||
|
"pr": 2473
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
50
contracts/integrations/contracts/src/ChainlinkStopLimit.sol
Normal file
50
contracts/integrations/contracts/src/ChainlinkStopLimit.sol
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./interfaces/IChainlinkAggregator.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract ChainlinkStopLimit {
|
||||||
|
|
||||||
|
/// @dev Checks that the price returned by the encoded Chainlink reference contract is
|
||||||
|
/// within the encoded price range.
|
||||||
|
/// @param stopLimitData Encodes the address of the Chainlink reference contract and the
|
||||||
|
/// valid price range.
|
||||||
|
function checkStopLimit(bytes calldata stopLimitData)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
{
|
||||||
|
(
|
||||||
|
address oracle,
|
||||||
|
int256 minPrice,
|
||||||
|
int256 maxPrice
|
||||||
|
) = abi.decode(
|
||||||
|
stopLimitData,
|
||||||
|
(address, int256, int256)
|
||||||
|
);
|
||||||
|
|
||||||
|
int256 latestPrice = IChainlinkAggregator(oracle).latestAnswer();
|
||||||
|
require(
|
||||||
|
latestPrice >= minPrice && latestPrice <= maxPrice,
|
||||||
|
"ChainlinkStopLimit/OUT_OF_PRICE_RANGE"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
|
// A subset of https://github.com/smartcontractkit/chainlink/blob/master/evm/contracts/interfaces/AggregatorInterface.sol
|
||||||
|
interface IChainlinkAggregator {
|
||||||
|
|
||||||
|
/// @dev Returns the latest data value recorded by the contract.
|
||||||
|
/// @return answer The latest data value recorded. For a price oracle aggregator, this will be
|
||||||
|
/// the price of the given asset in USD, multipled by 10^8
|
||||||
|
function latestAnswer() external view returns (int256 answer);
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "../src/interfaces/IChainlinkAggregator.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestChainlinkAggregator is
|
||||||
|
IChainlinkAggregator
|
||||||
|
{
|
||||||
|
int256 internal _price;
|
||||||
|
|
||||||
|
function setPrice(int256 price_)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_price = price_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function latestAnswer()
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (int256)
|
||||||
|
{
|
||||||
|
return _price;
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "TestFramework",
|
"publicInterfaceContracts": "TestFramework",
|
||||||
"abis": "./test/generated-artifacts/@(TestContractWrapper|TestDydxUser|TestEth2Dai|TestEth2DaiBridge|TestFramework|TestMainnetAggregatorFills|TestSignatureValidationWallet|TestUniswapBridge|TestUniswapExchange|TestUniswapExchangeFactory).json",
|
"abis": "./test/generated-artifacts/@(ChainlinkStopLimit|IChainlinkAggregator|TestChainlinkAggregator|TestContractWrapper|TestDydxUser|TestEth2Dai|TestEth2DaiBridge|TestFramework|TestMainnetAggregatorFills|TestSignatureValidationWallet|TestUniswapBridge|TestUniswapExchange|TestUniswapExchangeFactory).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
35
contracts/integrations/src/chainlink_utils.ts
Normal file
35
contracts/integrations/src/chainlink_utils.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { constants } from '@0x/contracts-test-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the given stop limit data parameters into the bytes format expected by the
|
||||||
|
* ChainlinkStopLimit contract.
|
||||||
|
*/
|
||||||
|
export function encodeChainlinkStopLimitData(oracle: string, minPrice: BigNumber, maxPrice: BigNumber): string {
|
||||||
|
const encoder = AbiEncoder.create([
|
||||||
|
{ name: 'oracle', type: 'address' },
|
||||||
|
{ name: 'minPrice', type: 'int256' },
|
||||||
|
{ name: 'maxPrice', type: 'int256' },
|
||||||
|
]);
|
||||||
|
return encoder.encode({ oracle, minPrice, maxPrice });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Encodes the given stop limit data parameters into StaticCall asset data so that it can be used
|
||||||
|
* in a 0x order.
|
||||||
|
*/
|
||||||
|
export function encodeStopLimitStaticCallData(
|
||||||
|
chainlinkStopLimitAddress: string,
|
||||||
|
oracle: string,
|
||||||
|
minPrice: BigNumber,
|
||||||
|
maxPrice: BigNumber,
|
||||||
|
): string {
|
||||||
|
const staticCallData = AbiEncoder.createMethod('checkStopLimit', [{ name: 'stopLimitData', type: 'bytes' }]).encode(
|
||||||
|
{ stopLimitData: encodeChainlinkStopLimitData(oracle, minPrice, maxPrice) },
|
||||||
|
);
|
||||||
|
return assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
chainlinkStopLimitAddress,
|
||||||
|
staticCallData,
|
||||||
|
constants.KECCAK256_NULL,
|
||||||
|
);
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export { artifacts } from './artifacts';
|
export { artifacts } from './artifacts';
|
||||||
export * from './wrappers';
|
export * from './wrappers';
|
||||||
|
export * from './chainlink_utils';
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as ChainlinkStopLimit from '../test/generated-artifacts/ChainlinkStopLimit.json';
|
||||||
|
import * as IChainlinkAggregator from '../test/generated-artifacts/IChainlinkAggregator.json';
|
||||||
|
import * as TestChainlinkAggregator from '../test/generated-artifacts/TestChainlinkAggregator.json';
|
||||||
import * as TestContractWrapper from '../test/generated-artifacts/TestContractWrapper.json';
|
import * as TestContractWrapper from '../test/generated-artifacts/TestContractWrapper.json';
|
||||||
import * as TestDydxUser from '../test/generated-artifacts/TestDydxUser.json';
|
import * as TestDydxUser from '../test/generated-artifacts/TestDydxUser.json';
|
||||||
import * as TestEth2Dai from '../test/generated-artifacts/TestEth2Dai.json';
|
import * as TestEth2Dai from '../test/generated-artifacts/TestEth2Dai.json';
|
||||||
@ -16,6 +19,9 @@ import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridg
|
|||||||
import * as TestUniswapExchange from '../test/generated-artifacts/TestUniswapExchange.json';
|
import * as TestUniswapExchange from '../test/generated-artifacts/TestUniswapExchange.json';
|
||||||
import * as TestUniswapExchangeFactory from '../test/generated-artifacts/TestUniswapExchangeFactory.json';
|
import * as TestUniswapExchangeFactory from '../test/generated-artifacts/TestUniswapExchangeFactory.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
|
ChainlinkStopLimit: ChainlinkStopLimit as ContractArtifact,
|
||||||
|
IChainlinkAggregator: IChainlinkAggregator as ContractArtifact,
|
||||||
|
TestChainlinkAggregator: TestChainlinkAggregator as ContractArtifact,
|
||||||
TestContractWrapper: TestContractWrapper as ContractArtifact,
|
TestContractWrapper: TestContractWrapper as ContractArtifact,
|
||||||
TestDydxUser: TestDydxUser as ContractArtifact,
|
TestDydxUser: TestDydxUser as ContractArtifact,
|
||||||
TestEth2Dai: TestEth2Dai as ContractArtifact,
|
TestEth2Dai: TestEth2Dai as ContractArtifact,
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
import { ExchangeRevertErrors } from '@0x/contracts-exchange';
|
||||||
|
import { blockchainTests, constants, expect, orderHashUtils } from '@0x/contracts-test-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber, StringRevertError } from '@0x/utils';
|
||||||
|
|
||||||
|
import { encodeStopLimitStaticCallData } from '../../src/chainlink_utils';
|
||||||
|
|
||||||
|
import { artifacts } from '../artifacts';
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
|
import { Maker } from '../framework/actors/maker';
|
||||||
|
import { Taker } from '../framework/actors/taker';
|
||||||
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
|
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
|
||||||
|
import { DeploymentManager } from '../framework/deployment_manager';
|
||||||
|
import { ChainlinkStopLimitContract, TestChainlinkAggregatorContract } from '../wrappers';
|
||||||
|
|
||||||
|
blockchainTests.resets('Chainlink stop-limit order tests', env => {
|
||||||
|
let deployment: DeploymentManager;
|
||||||
|
let balanceStore: BlockchainBalanceStore;
|
||||||
|
let initialBalances: LocalBalanceStore;
|
||||||
|
|
||||||
|
let chainLinkAggregator: TestChainlinkAggregatorContract;
|
||||||
|
|
||||||
|
let maker: Maker;
|
||||||
|
let taker: Taker;
|
||||||
|
|
||||||
|
let order: SignedOrder;
|
||||||
|
|
||||||
|
const minPrice = new BigNumber(42);
|
||||||
|
const maxPrice = new BigNumber(1337);
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
deployment = await DeploymentManager.deployAsync(env, {
|
||||||
|
numErc20TokensToDeploy: 2,
|
||||||
|
numErc721TokensToDeploy: 0,
|
||||||
|
numErc1155TokensToDeploy: 0,
|
||||||
|
});
|
||||||
|
const [makerToken, takerToken] = deployment.tokens.erc20;
|
||||||
|
|
||||||
|
const chainlinkStopLimit = await ChainlinkStopLimitContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.ChainlinkStopLimit,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
);
|
||||||
|
chainLinkAggregator = await TestChainlinkAggregatorContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestChainlinkAggregator,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
);
|
||||||
|
|
||||||
|
const makerAssetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(makerToken.address),
|
||||||
|
encodeStopLimitStaticCallData(
|
||||||
|
chainlinkStopLimit.address,
|
||||||
|
chainLinkAggregator.address,
|
||||||
|
minPrice,
|
||||||
|
maxPrice,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const orderConfig = {
|
||||||
|
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||||
|
makerAssetData,
|
||||||
|
takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address),
|
||||||
|
makerFeeAssetData: constants.NULL_BYTES,
|
||||||
|
takerFeeAssetData: constants.NULL_BYTES,
|
||||||
|
makerFee: constants.ZERO_AMOUNT,
|
||||||
|
takerFee: constants.ZERO_AMOUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
maker = new Maker({
|
||||||
|
name: 'Maker',
|
||||||
|
deployment,
|
||||||
|
orderConfig,
|
||||||
|
});
|
||||||
|
taker = new Taker({ name: 'Taker', deployment });
|
||||||
|
|
||||||
|
// Set balances and allowances
|
||||||
|
await maker.configureERC20TokenAsync(makerToken);
|
||||||
|
await taker.configureERC20TokenAsync(takerToken);
|
||||||
|
|
||||||
|
order = await maker.signOrderAsync();
|
||||||
|
|
||||||
|
// Set up balance stores
|
||||||
|
const tokenOwners = {
|
||||||
|
Maker: maker.address,
|
||||||
|
Taker: taker.address,
|
||||||
|
};
|
||||||
|
const tokenContracts = {
|
||||||
|
erc20: { makerToken, takerToken },
|
||||||
|
};
|
||||||
|
balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts);
|
||||||
|
await balanceStore.updateBalancesAsync();
|
||||||
|
initialBalances = LocalBalanceStore.create(balanceStore);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fillOrder reverts if price < minPrice', async () => {
|
||||||
|
await chainLinkAggregator.setPrice(minPrice.minus(1)).awaitTransactionSuccessAsync();
|
||||||
|
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||||
|
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||||
|
orderHashUtils.getOrderHashHex(order),
|
||||||
|
order.makerAssetData,
|
||||||
|
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||||
|
);
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
it('fillOrder reverts price > maxPrice', async () => {
|
||||||
|
await chainLinkAggregator.setPrice(maxPrice.plus(1)).awaitTransactionSuccessAsync();
|
||||||
|
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||||
|
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||||
|
orderHashUtils.getOrderHashHex(order),
|
||||||
|
order.makerAssetData,
|
||||||
|
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||||
|
);
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
it('fillOrder succeeds if price = minPrice', async () => {
|
||||||
|
await chainLinkAggregator.setPrice(minPrice).awaitTransactionSuccessAsync();
|
||||||
|
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||||
|
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||||
|
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||||
|
await balanceStore.updateBalancesAsync();
|
||||||
|
balanceStore.assertEquals(expectedBalances);
|
||||||
|
});
|
||||||
|
it('fillOrder succeeds if price = maxPrice', async () => {
|
||||||
|
await chainLinkAggregator.setPrice(maxPrice).awaitTransactionSuccessAsync();
|
||||||
|
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||||
|
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||||
|
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||||
|
await balanceStore.updateBalancesAsync();
|
||||||
|
balanceStore.assertEquals(expectedBalances);
|
||||||
|
});
|
||||||
|
it('fillOrder succeeds if minPrice < price < maxPrice', async () => {
|
||||||
|
await chainLinkAggregator
|
||||||
|
.setPrice(minPrice.plus(maxPrice).dividedToIntegerBy(2))
|
||||||
|
.awaitTransactionSuccessAsync();
|
||||||
|
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||||
|
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||||
|
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||||
|
await balanceStore.updateBalancesAsync();
|
||||||
|
balanceStore.assertEquals(expectedBalances);
|
||||||
|
});
|
||||||
|
});
|
@ -3,6 +3,9 @@
|
|||||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
export * from '../test/generated-wrappers/chainlink_stop_limit';
|
||||||
|
export * from '../test/generated-wrappers/i_chainlink_aggregator';
|
||||||
|
export * from '../test/generated-wrappers/test_chainlink_aggregator';
|
||||||
export * from '../test/generated-wrappers/test_contract_wrapper';
|
export * from '../test/generated-wrappers/test_contract_wrapper';
|
||||||
export * from '../test/generated-wrappers/test_dydx_user';
|
export * from '../test/generated-wrappers/test_dydx_user';
|
||||||
export * from '../test/generated-wrappers/test_eth2_dai';
|
export * from '../test/generated-wrappers/test_eth2_dai';
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": [
|
"files": [
|
||||||
"generated-artifacts/TestFramework.json",
|
"generated-artifacts/TestFramework.json",
|
||||||
|
"test/generated-artifacts/ChainlinkStopLimit.json",
|
||||||
|
"test/generated-artifacts/IChainlinkAggregator.json",
|
||||||
|
"test/generated-artifacts/TestChainlinkAggregator.json",
|
||||||
"test/generated-artifacts/TestContractWrapper.json",
|
"test/generated-artifacts/TestContractWrapper.json",
|
||||||
"test/generated-artifacts/TestDydxUser.json",
|
"test/generated-artifacts/TestDydxUser.json",
|
||||||
"test/generated-artifacts/TestEth2Dai.json",
|
"test/generated-artifacts/TestEth2Dai.json",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "4.6.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added ChainlinkStopLimit addresses (mainnet, ropsten, rinkeby)",
|
||||||
|
"pr": 2473
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
||||||
"dydxBridge": "0x55dc8f21d20d4c6ed3c82916a438a413ca68e335",
|
"dydxBridge": "0x55dc8f21d20d4c6ed3c82916a438a413ca68e335",
|
||||||
"godsUnchainedValidator": "0x09A379Ef7218BCFD8913fAa8B281ebc5A2E0bC04",
|
"godsUnchainedValidator": "0x09A379Ef7218BCFD8913fAa8B281ebc5A2E0bC04",
|
||||||
"broker": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0"
|
"broker": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0",
|
||||||
|
"chainlinkStopLimit": "0xeb27220f95f364e1d9531992c48613f231839f53"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"erc20Proxy": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
|
"erc20Proxy": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
|
||||||
@ -55,7 +56,8 @@
|
|||||||
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"godsUnchainedValidator": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0",
|
"godsUnchainedValidator": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0",
|
||||||
"broker": "0x4Aa817C6f383C8e8aE77301d18Ce48efb16Fd2BE"
|
"broker": "0x4Aa817C6f383C8e8aE77301d18Ce48efb16Fd2BE",
|
||||||
|
"chainlinkStopLimit": "0x67a094cf028221ffdd93fc658f963151d05e2a74"
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"exchangeV2": "0xbff9493f92a3df4b0429b6d00743b3cfb4c85831",
|
"exchangeV2": "0xbff9493f92a3df4b0429b6d00743b3cfb4c85831",
|
||||||
@ -84,7 +86,8 @@
|
|||||||
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
||||||
"broker": "0x0000000000000000000000000000000000000000"
|
"broker": "0x0000000000000000000000000000000000000000",
|
||||||
|
"chainlinkStopLimit": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a"
|
||||||
},
|
},
|
||||||
"42": {
|
"42": {
|
||||||
"erc20Proxy": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e",
|
"erc20Proxy": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e",
|
||||||
@ -113,7 +116,8 @@
|
|||||||
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
||||||
"broker": "0x0000000000000000000000000000000000000000"
|
"broker": "0x0000000000000000000000000000000000000000",
|
||||||
|
"chainlinkStopLimit": "0x0000000000000000000000000000000000000000"
|
||||||
},
|
},
|
||||||
"1337": {
|
"1337": {
|
||||||
"erc20Proxy": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48",
|
"erc20Proxy": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48",
|
||||||
@ -142,6 +146,7 @@
|
|||||||
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
||||||
"broker": "0x0000000000000000000000000000000000000000"
|
"broker": "0x0000000000000000000000000000000000000000",
|
||||||
|
"chainlinkStopLimit": "0x0000000000000000000000000000000000000000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user