Added mainnet DydxBridge integration tests with dYdX SoloMargin contract
This commit is contained in:
159
contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts
Normal file
159
contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import {
|
||||
artifacts as assetProxyArtifacts,
|
||||
DydxBridgeActionType,
|
||||
DydxBridgeContract,
|
||||
DydxBridgeData,
|
||||
dydxBridgeDataEncoder,
|
||||
} from '@0x/contracts-asset-proxy';
|
||||
import { artifacts as erc20Artifacts } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, describe, expect, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { contractAddresses, dydxAccountOwner } from '../mainnet_fork_utils';
|
||||
|
||||
import { dydxEvents } from './abi/dydxEvents';
|
||||
|
||||
blockchainTests.resets.fork('Mainnet dydx bridge tests', env => {
|
||||
let testContract: DydxBridgeContract;
|
||||
// random account to receive tokens from dydx
|
||||
const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308';
|
||||
const defaultAccountNumber = new BigNumber(0);
|
||||
const daiMarketId = new BigNumber(3);
|
||||
const defaultAmount = toBaseUnitAmount(1);
|
||||
const defaultDepositAction = {
|
||||
actionType: DydxBridgeActionType.Deposit as number,
|
||||
accountId: constants.ZERO_AMOUNT,
|
||||
marketId: daiMarketId,
|
||||
conversionRateNumerator: constants.ZERO_AMOUNT,
|
||||
conversionRateDenominator: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const defaultWithdrawAction = {
|
||||
actionType: DydxBridgeActionType.Withdraw as number,
|
||||
accountId: constants.ZERO_AMOUNT,
|
||||
marketId: daiMarketId,
|
||||
// This ratio must be less than the `1` to account
|
||||
// for interest in dydx balances because the test
|
||||
// account has an initial dydx balance of zero.
|
||||
conversionRateNumerator: new BigNumber(1),
|
||||
conversionRateDenominator: new BigNumber(2),
|
||||
};
|
||||
before(async () => {
|
||||
testContract = new DydxBridgeContract(contractAddresses.dydxBridge, env.provider, env.txDefaults, {
|
||||
DydxBridge: assetProxyArtifacts.DydxBridge.compilerOutput.abi,
|
||||
ERC20: erc20Artifacts.ERC20Token.compilerOutput.abi,
|
||||
Dydx: dydxEvents.abi,
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
const callAndVerifyDydxEvents = async (bridgeData: DydxBridgeData): Promise<void> => {
|
||||
const txReceipt = await testContract
|
||||
.bridgeTransferFrom(
|
||||
constants.NULL_ADDRESS,
|
||||
dydxAccountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
dydxBridgeDataEncoder.encode({ bridgeData }),
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: contractAddresses.erc20BridgeProxy, gasPrice: 0 });
|
||||
|
||||
// Construct expected events
|
||||
const expectedDepositEvents = [];
|
||||
const expectedWithdrawEvents = [];
|
||||
for (const action of bridgeData.actions) {
|
||||
const scaledAmount = action.conversionRateDenominator.gt(0)
|
||||
? defaultAmount
|
||||
.times(action.conversionRateNumerator)
|
||||
.dividedToIntegerBy(action.conversionRateDenominator)
|
||||
: defaultAmount;
|
||||
switch (action.actionType) {
|
||||
case DydxBridgeActionType.Deposit:
|
||||
expectedDepositEvents.push({
|
||||
accountOwner: dydxAccountOwner,
|
||||
accountNumber: bridgeData.accountNumbers[action.accountId.toNumber()],
|
||||
market: action.marketId,
|
||||
update: [[true, scaledAmount]],
|
||||
from: dydxAccountOwner,
|
||||
});
|
||||
break;
|
||||
|
||||
case DydxBridgeActionType.Withdraw:
|
||||
expectedWithdrawEvents.push({
|
||||
accountOwner: dydxAccountOwner,
|
||||
accountNumber: bridgeData.accountNumbers[action.accountId.toNumber()],
|
||||
market: action.marketId,
|
||||
update: [[false, scaledAmount]],
|
||||
to: receiver,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unrecognized Action: ${action.actionType}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify events
|
||||
let nextExpectedDepositEventIdx = 0;
|
||||
let nextExpectedWithdrawEventIdx = 0;
|
||||
for (const rawLog of txReceipt.logs) {
|
||||
// tslint:disable-next-line no-unnecessary-type-assertion
|
||||
const log = rawLog as LogWithDecodedArgs<DecodedLogArgs>;
|
||||
if (log.event !== 'LogDeposit' && log.event !== 'LogWithdraw') {
|
||||
continue;
|
||||
}
|
||||
const expectedEvent =
|
||||
log.event === 'LogDeposit'
|
||||
? expectedDepositEvents[nextExpectedDepositEventIdx++]
|
||||
: expectedWithdrawEvents[nextExpectedWithdrawEventIdx++];
|
||||
expect(expectedEvent.accountOwner, 'accountOwner').to.equal(log.args.accountOwner);
|
||||
expect(expectedEvent.accountNumber, 'accountNumber').to.bignumber.equal(log.args.accountNumber);
|
||||
expect(expectedEvent.market, 'market').to.bignumber.equal(log.args.market);
|
||||
expect(expectedEvent.from, 'from').to.equal(log.args.from);
|
||||
// We only check the first update field because it's the delta balance (amount deposited).
|
||||
// The next field is the new total, which depends on interest rates at the time of execution.
|
||||
expect(expectedEvent.update[0][0], 'update sign').to.equal(log.args.update[0][0]);
|
||||
const updateValueHex = log.args.update[0][1]._hex;
|
||||
const updateValueBn = new BigNumber(updateValueHex, 16);
|
||||
expect(expectedEvent.update[0][1], 'update value').to.bignumber.equal(updateValueBn);
|
||||
}
|
||||
};
|
||||
|
||||
it('succeeds when calling `operate` with the `deposit` action and a single account', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
});
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultDepositAction],
|
||||
});
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction],
|
||||
});
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction],
|
||||
});
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
});
|
||||
});
|
||||
it('succeeds when calling `operate` with multiple actions under a single account', async () => {
|
||||
await callAndVerifyDydxEvents({
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,5 +5,6 @@ import { provider } from '@0x/contracts-test-utils';
|
||||
const chainId = 1;
|
||||
const contractAddresses = getContractAddressesForChainOrThrow(chainId);
|
||||
const contractWrappers = new ContractWrappers(provider, { chainId, contractAddresses });
|
||||
const dydxAccountOwner = '0xbd67dce6348dc5949a8af5888d6a2bd5dc3cb86d';
|
||||
|
||||
export { contractAddresses, contractWrappers };
|
||||
export { contractAddresses, contractWrappers, dydxAccountOwner };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||
import { devConstants, env, EnvVars, Web3Config, web3Factory } from '@0x/dev-utils';
|
||||
import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders';
|
||||
import { logUtils } from '@0x/utils';
|
||||
@@ -26,11 +27,15 @@ if (process.env.FORK_RPC_URL !== undefined) {
|
||||
...providerConfigs,
|
||||
fork: process.env.FORK_RPC_URL,
|
||||
blockTime: 0,
|
||||
// ZeroExGovernor signer addresses
|
||||
unlocked_accounts: [
|
||||
// ZeroExGovernor signer addresses
|
||||
'0x257619b7155d247e43c8b6d90c8c17278ae481f0',
|
||||
'0x5ee2a00f8f01d099451844af7f894f26a57fcbf2',
|
||||
'0x894d623e0e0e8ed12c4a73dada999e275684a37d',
|
||||
// Test dYdX user account (can trade DAI on dydx bridge)
|
||||
'0xbd67dce6348dc5949a8af5888d6a2bd5dc3cb86d',
|
||||
// ERC20BridgeProxy
|
||||
getContractAddressesForChainOrThrow(1).erc20BridgeProxy,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user