diff --git a/.circleci/config.yml b/.circleci/config.yml index 2fdecc59..98727412 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,7 +50,7 @@ jobs: docker: - image: circleci/node:9.11.1 working_directory: ~/protocol - parallelism: 2 + parallelism: 3 steps: - restore_cache: key: protocol-completed-build-{{ .Environment.CIRCLE_SHA1 }} diff --git a/README.md b/README.md index 0c1ac16d..b4f8d47f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,75 @@ Source code for Ethereum Smart Contracts used by the dYdX Margin Trading Protoco [Short & Leveraged Long Tokens Whitepaper](https://margintokens.dydx.exchange) -### Development +## Npm Package + +The npm package contains the deployed addresses of the contracts, and also allows access to seed positions and orders on the docker test container + +#### Install + +``` +npm install --save @dydxprotocol/protocol +``` + +#### Contracts + +```javascript +import { Margin as MarginContract } from '@dydxprotocol/protocol'; +import truffleContract from 'truffle-contract'; + +async function openPosition(provider, networkId) { + const Margin = truffleContract(MarginContract); + + Margin.setProvider(provider); + Margin.setNetwork(networkId); + + const margin = await Margin.deployed(); + + await margin.openPosition(...); +} +``` + +#### Seed Positions / Orders + +Seed positions are available and already deployed on the docker container + +```javascript +import { seeds } from '@dydxprotocol/protocol'; + +const position = seeds.positions[2]; + +console.log(position.id); +console.log(position.isTokenized); + +// Test 0x V1 orders. Maker already has balance and allowance set +const order = seeds.orders[1]; + +console.log(order.maker); +``` + +## Docker Container + +[Docker container](https://hub.docker.com/r/dydxprotocol/protocol/) with a a deployed version of the protocol running on a ganache-cli node with network_id = 1212 + +``` +docker pull dydxprotocol/protocol +docker run dydxprotocol/protocol +``` + +#### Docker Compose + +``` +# docker-compose.yml + +version: '3' +services: + protocol: + image: dydxprotocol/protocol:latest + ports: + - 8545:8545 +``` + +## Development #### Install diff --git a/migrations/3_positions.js b/migrations/3_positions.js index 003e6213..729a15ec 100644 --- a/migrations/3_positions.js +++ b/migrations/3_positions.js @@ -1,13 +1,36 @@ +/* + + Copyright 2018 dYdX Trading Inc. + + 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. + +*/ + global.artifacts = artifacts; global.web3 = web3; const fs = require('fs'); const promisify = require("es6-promisify"); const Margin = artifacts.require('Margin'); +const ZeroExProxy = artifacts.require('ZeroExProxy'); +const TestToken = artifacts.require('TestToken'); const { isDevNetwork } = require('./helpers'); const { snapshot } = require('../src/snapshots'); const { doOpenPosition, getPosition } = require('../test/helpers/MarginHelper'); const { createShortToken } = require('../test/helpers/ERC20PositionHelper'); +const { ADDRESSES } = require('../test/helpers/Constants'); +const { createSignedBuyOrder, createSignedSellOrder } = require('../test/helpers/ZeroExHelper'); +const { issueAndSetAllowance } = require('../test/helpers/TokenHelper'); web3.currentProvider.sendAsync = web3.currentProvider.send; @@ -15,28 +38,61 @@ const writeFileAsync = promisify(fs.writeFile); async function doMigration(deployer, network, accounts) { if (isDevNetwork(network)) { - let salt = 729436712; - const openTransactions = []; + const seeds = {}; + + // Needs to complete before createSeedOrders + const positions = await createSeedPositions(accounts); - openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); - openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); - openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); - openTransactions.push(await createShortToken(accounts, { salt: salt++ })); + const orders = await createSeedOrders(accounts); await snapshot(web3); - const margin = await Margin.deployed(); - const positions = await Promise.all(openTransactions.map(t => getPosition(margin, t.id))); - for (let i = 0; i < openTransactions.length; i++) { - positions[i].id = openTransactions[i].id; + seeds.positions = positions; + seeds.orders = orders; - positions[i].isTokenized = i === 3 ? true : false; - } + const json = JSON.stringify(seeds, null, 4); + await writeFileAsync(__dirname + '/../build/seeds.json', json, 'utf8'); + } +} - const json = JSON.stringify(positions, null, 4); +async function createSeedPositions(accounts) { + let salt = 729436712; + const openTransactions = []; - await writeFileAsync(__dirname + '/../build/test-positions.json', json, 'utf8'); + openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); + openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); + openTransactions.push(await doOpenPosition(accounts, { salt: salt++ })); + openTransactions.push(await createShortToken(accounts, { salt: salt++ })); + + const margin = await Margin.deployed(); + const positions = await Promise.all(openTransactions.map(t => getPosition(margin, t.id))); + for (let i = 0; i < openTransactions.length; i++) { + positions[i].id = openTransactions[i].id; + + positions[i].isTokenized = i === 3 ? true : false; } + + return positions; +} + +async function createSeedOrders(accounts) { + const orders = await Promise.all([ + createSignedBuyOrder(accounts, { salt: 7294234423, feeRecipient: ADDRESSES.ZERO }), + createSignedSellOrder(accounts, { salt: 7294234424, feeRecipient: ADDRESSES.ZERO }), + ]); + + const makerTokens = await Promise.all(orders.map(order => TestToken.at(order.makerTokenAddress))); + + await Promise.all(orders.map((order, i) => { + return issueAndSetAllowance( + makerTokens[i], + order.maker, + order.makerTokenAmount, + ZeroExProxy.address, + ) + })); + + return orders; } module.exports = (deployer, network, accounts) => { diff --git a/migrations/deployed.json b/migrations/deployed.json index 745db687..31216a73 100644 --- a/migrations/deployed.json +++ b/migrations/deployed.json @@ -2,82 +2,82 @@ "Margin": { "42": { "links": { - "OpenPositionImpl": "0xc57f874e8fd9c4b063f74b34b8ee1daddc19a225", - "ClosePositionImpl": "0xede8bf43e1c3cb8dd13c480f54b843d6736ae6b6", - "CloseWithoutCounterpartyImpl": "0xda75cc2749264046c14b5b7a9fa1a7d56ed72e2e", - "InterestImpl": "0x4313cca8f702e67dfc784f4778c939c6b3620514", - "ForceRecoverCollateralImpl": "0xb984fdf85b814b465eff2396d18b7b78163da029", - "LoanImpl": "0xef4f4be07b3d5141c4566caff3567191948d669c", - "DepositCollateralImpl": "0xa2710483fb528f3b11f20be6e3f701633dcfbaf4", - "TransferImpl": "0xfdf8cb392ec70bb0752165fda3961dc3ac55af17", - "IncreasePositionImpl": "0x70a93396b17f623df4c4c9d222252829055f892a", - "OpenWithoutCounterpartyImpl": "0x24751749816ba6c0f6d0b2066208e78e8d6553c5" + "OpenPositionImpl": "0x80c0a99ca66037ae2e3f24263f8ea33dcccde660", + "ClosePositionImpl": "0xe0801ec05ec28c0e37d317a3b65edc77e282dd7e", + "CloseWithoutCounterpartyImpl": "0x49e491e24db10fb6e18d44bc393ab810578d268e", + "InterestImpl": "0xef9e1da100c11921e0e5c2947803f2568cdf124f", + "ForceRecoverCollateralImpl": "0x6084687121012385a5d575ac79c96579f321c704", + "LoanImpl": "0xdbdd4c71ca86bb900dada85ac82606fa9de9a8ce", + "DepositCollateralImpl": "0xf9a620b838dbab2ff3852cf0628e7d91cb6dc884", + "TransferImpl": "0xeffa64aaecf4413f852a8b466b7c6c043e5c029b", + "IncreasePositionImpl": "0xa8f79249f276a0c0081d22ad7325543594833afd", + "OpenWithoutCounterpartyImpl": "0x2d571ab0a11f9f5a61399fd095491d629db0dc56" }, - "address": "0xe97da4a12ee7feafddfdd4766d2705f2ee993d6a", - "transactionHash": "0x1a785ff423c1bcf0ef45dae335eff194ee42b4c0c1586f0505f5f49bb3abc838" + "address": "0x2b450acee236905b2dc1bbb0598efdae46fb33f9", + "transactionHash": "0xc9952d8daac018ab0d076717534ea89751ca2ab4875749cd99def3f090e8a76f" } }, "Vault": { "42": { "links": {}, - "address": "0x4fdc15f9e00316cf114bc4389c12c79ae0344175", - "transactionHash": "0xd49f2f3a8bc98018065bb853b1c6a925b1440b694f3916fd9a87e7c4e15dd967" + "address": "0xe7c670aa1fb066944bb87f25f168139fbcf7995d", + "transactionHash": "0xe3c050602a6320ad639c295c2116b8ac8b51c6392778c344b7be9d8ab5f92c4d" } }, "TokenProxy": { "42": { "links": {}, - "address": "0x12262ee5a32b3892a3fce087ff7a3299c0f8813f", - "transactionHash": "0x27f1dd56296bb2ad8358b037f14dfca948fe60f24b7f4b1caf2db33b1d6cb843" + "address": "0xf72b99ac1f548efe5ce170aaa9c0a733d1c4d1b3", + "transactionHash": "0x4c31bfb5b393647e13e20ba6c87dfd6231cbf8c8ef0d5912674d39eef9de73bd" } }, "DutchAuctionCloser": { "42": { "links": {}, - "address": "0x4e338944afbace1f1095b1fde436f91e79d11486", - "transactionHash": "0x3fb3d77bd3e4e54c1e9bcf22429b9fb3f59ec094d035d2f85773e15b0b0bf89b" + "address": "0x46cf0df6d56cfc40cfb5fcff9ef38e381dd57dbd", + "transactionHash": "0x754760abb136b0543780de16df8ea4d56604766146b4f6d4022cf38f3ad81dd9" } }, "SharedLoanCreator": { "42": { "links": {}, - "address": "0x49f2bff73a6c47391133022522725b9d2b62498c", - "transactionHash": "0x0e483662d2d7b140fe3cb51ff13f99c76ba75b65ae396d7ab60ae157cfca9e65" + "address": "0x12506202ce98fc79bef1e5a98f95aba22ebe1908", + "transactionHash": "0xcbe1ab7eada0c7f45adcbfbbd4a8c7d36ba9a4d03e8359d4bdf5fc341aeab132" } }, "ERC20ShortCreator": { "42": { "links": {}, - "address": "0x1979bb1aa89b8f35ce1a891b4e7508faca07c01c", - "transactionHash": "0x8a970b3d9cde9363d74885875c0453341bfc026969335f88bf98db84338f2d72" + "address": "0xf735889abd1e3ab3f0a74c80f0558d4d8c022624", + "transactionHash": "0xc243a0b3995a06f6f7548fb58c0902c3cd75503440e0951981627c3f76cdbb4f" } }, "ERC20LongCreator": { "42": { "links": {}, - "address": "0x8adf53551449c56394c2952ed8f01604e0de2683", - "transactionHash": "0xe46e2940a6301ceb0199e39e014451818665bbba20041ac198ee30989d68d81b" + "address": "0xf62afab8e98f44a8ac863dd94d297825833c78ce", + "transactionHash": "0x6a4b9547e38da0a0c7efd820fc41a5bdca83389ec3f4d4e85f74bc52a4ba69c6" } }, "ERC721MarginPosition": { "42": { "links": {}, - "address": "0x3d1720538d31c5a396deb00ab9956dec072a6423", - "transactionHash": "0xd659dcf0b6623966fe9a3cca1fceba0e7bc29d768b746e9ce940ef1b599433bc" + "address": "0x0de60513e2ed16d16856fa6f6c05d34e9e3637a4", + "transactionHash": "0x4681720ce633964e7bebbb136e0b57829e93d5123f44e2e6a3bd2483db654b8a" } }, "ZeroExExchangeWrapper": { "42": { "links": {}, - "address": "0x721976badf842a263f8d1a5d64c5578a4368f330", - "transactionHash": "0x9dab35bd6ebd6df6e110c0d3f16035e759bf4ac2165b25253ebc652981c6f9b0" + "address": "0xb604adc66574c028c5fab82ef031bcbc6e63a929", + "transactionHash": "0x5035d2b31bae862b6503b13b199ad2e068b528c33176642a9999378dd47735d9" } }, "OpenDirectlyExchangeWrapper": { "42": { "links": {}, - "address": "0x5aab90bacc2d3d6eb1d208920bdb0b3c3278e24d", - "transactionHash": "0xdedcffadc3992c9a0a40b02118763cd70ecb72ca82d643a4e410bb535a3beef0" + "address": "0xa9dd2ba28aa2e6db9c76f62b32161a2778d4aab6", + "transactionHash": "0xabc29f85d4787b16de56845afe34d5110ce0389e949211ef76457cd7c05980f8" } } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d6f17175..3d511156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dydxprotocol/protocol", - "version": "0.1.13", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 00caa1ce..b14a6dc6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dydxprotocol/protocol", - "version": "0.1.13", + "version": "0.2.0", "description": "Ethereum Smart Contracts for the dYdX Margin Trading Protocol", "main": "build/index.js", "files": [ @@ -33,7 +33,7 @@ "build:js": "./node_modules/.bin/babel src --out-dir build/ --source-maps inline", "docker_node": "ganache-cli -i 1212 -d -p 8545 -h 0.0.0.0 --db=/home/.ganache", "clean_contract_json": "babel-node ./scripts/clean-build.js", - "save_deployed_addresses": "babel-node ./scripts/save-deployed-addresses.js" + "deploy_kovan": "truffle migrate --network=kovan --reset && babel-node ./scripts/save-deployed-addresses.js" }, "repository": { "type": "git", diff --git a/src/contracts.js b/src/contracts.js index 4e395a0a..9286cb4c 100644 --- a/src/contracts.js +++ b/src/contracts.js @@ -1,3 +1,21 @@ +/* + + Copyright 2018 dYdX Trading Inc. + + 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. + +*/ + export { default as Margin } from '../build/contracts/Margin.json'; export { default as Vault } from '../build/contracts/Vault.json'; export { default as TokenProxy } from '../build/contracts/TokenProxy.json'; diff --git a/src/index.js b/src/index.js index 59d646c3..aefaa1e8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,21 @@ +/* + + Copyright 2018 dYdX Trading Inc. + + 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. + +*/ + export * from './contracts'; export * from './snapshots'; -export * from './test-positions'; +export { default as seeds } from './seeds'; diff --git a/src/seeds.js b/src/seeds.js new file mode 100644 index 00000000..2908380f --- /dev/null +++ b/src/seeds.js @@ -0,0 +1,51 @@ +/* + + Copyright 2018 dYdX Trading Inc. + + 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. + +*/ + +import BigNumber from 'bignumber.js'; +import SeedsJson from '../build/seeds.json'; + +SeedsJson.positions = SeedsJson.positions.map(mapPositionFromJson); +SeedsJson.orders = SeedsJson.orders.map(mapOrderFromJson); + +export default SeedsJson; + +function mapPositionFromJson(jsonPosition) { + return { + ...jsonPosition, + position: new BigNumber(jsonPosition.principal), + interestRate: new BigNumber(jsonPosition.interestRate), + requiredDeposit: new BigNumber(jsonPosition.requiredDeposit), + callTimeLimit: new BigNumber(jsonPosition.callTimeLimit), + callTimestamp: new BigNumber(jsonPosition.callTimestamp), + startTimestamp: new BigNumber(jsonPosition.startTimestamp), + maxDuration: new BigNumber(jsonPosition.maxDuration), + interestPeriod: new BigNumber(jsonPosition.interestPeriod), + } +} + +function mapOrderFromJson(jsonOrder) { + return { + ...jsonOrder, + expirationUnixTimestampSec: new BigNumber(jsonOrder.expirationUnixTimestampSec), + makerFee: new BigNumber(jsonOrder.makerFee), + salt: new BigNumber(jsonOrder.salt), + takerFee: new BigNumber(jsonOrder.takerFee), + makerTokenAmount: new BigNumber(jsonOrder.makerTokenAmount), + takerTokenAmount: new BigNumber(jsonOrder.takerTokenAmount), + }; +} diff --git a/src/snapshots.js b/src/snapshots.js index 72172c2e..ac4c9f54 100644 --- a/src/snapshots.js +++ b/src/snapshots.js @@ -1,3 +1,21 @@ +/* + + Copyright 2018 dYdX Trading Inc. + + 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. + +*/ + import promisify from "es6-promisify"; export async function reset(web3Instance, id) { diff --git a/src/test-positions.js b/src/test-positions.js deleted file mode 100644 index 99a4dd4c..00000000 --- a/src/test-positions.js +++ /dev/null @@ -1,18 +0,0 @@ -import BigNumber from 'bignumber.js'; -import TestPositionsJson from '../build/test-positions.json'; - -export const TEST_POSITIONS = TestPositionsJson.map(mapPositionFromJson); - -function mapPositionFromJson(jsonPosition) { - return { - ...jsonPosition, - position: new BigNumber(jsonPosition.principal), - interestRate: new BigNumber(jsonPosition.interestRate), - requiredDeposit: new BigNumber(jsonPosition.requiredDeposit), - callTimeLimit: new BigNumber(jsonPosition.callTimeLimit), - callTimestamp: new BigNumber(jsonPosition.callTimestamp), - startTimestamp: new BigNumber(jsonPosition.startTimestamp), - maxDuration: new BigNumber(jsonPosition.maxDuration), - interestPeriod: new BigNumber(jsonPosition.interestPeriod), - } -} diff --git a/test/helpers/ZeroExHelper.js b/test/helpers/ZeroExHelper.js index 0b41ce10..8b6ea206 100644 --- a/test/helpers/ZeroExHelper.js +++ b/test/helpers/ZeroExHelper.js @@ -4,7 +4,6 @@ const Web3 = require('web3'); const BigNumber = require('bignumber.js'); const HeldToken = artifacts.require("TokenA"); const OwedToken = artifacts.require("TokenB"); -const FeeToken = artifacts.require("TokenC"); const promisify = require("es6-promisify"); const ethUtil = require('ethereumjs-util'); const { DEFAULT_SALT, ORDER_TYPE } = require('./Constants'); @@ -16,14 +15,15 @@ const BASE_AMOUNT = new BigNumber('1098623452345987123') async function createSignedSellOrder( accounts, { - salt = DEFAULT_SALT + salt = DEFAULT_SALT, + feeRecipient, } = {} ) { let order = { type: ORDER_TYPE.ZERO_EX, exchangeContractAddress: ZeroExExchange.address, expirationUnixTimestampSec: new BigNumber(100000000000000), - feeRecipient: accounts[6], + feeRecipient: feeRecipient || accounts[6], maker: accounts[5], makerFee: BASE_AMOUNT.times(0.010928345).floor(), salt: new BigNumber(salt), @@ -47,21 +47,20 @@ async function createSignedSellOrder( async function createSignedBuyOrder( accounts, { - salt = DEFAULT_SALT + salt = DEFAULT_SALT, + feeRecipient, } = {} ) { let order = { type: ORDER_TYPE.ZERO_EX, exchangeContractAddress: ZeroExExchange.address, expirationUnixTimestampSec: new BigNumber(100000000000000), - feeRecipient: accounts[4], + feeRecipient: feeRecipient || accounts[4], maker: accounts[2], makerFee: BASE_AMOUNT.times(.02012398).floor(), salt: new BigNumber(salt), taker: ZeroEx.NULL_ADDRESS, takerFee: BASE_AMOUNT.times(.1019238).floor(), - makerFeeTokenAddress: FeeToken.address, - takerFeeTokenAddress: FeeToken.address, // heldToken makerTokenAddress: HeldToken.address, diff --git a/test/tests/js/TestTesting.js b/test/tests/js/TestTesting.js index fcb72262..60d73e13 100644 --- a/test/tests/js/TestTesting.js +++ b/test/tests/js/TestTesting.js @@ -1,12 +1,15 @@ -const { TEST_POSITIONS, reset, snapshot } = require('../../../src/index'); +const { seeds, reset, snapshot } = require('../../../src/index'); const { getPosition } = require('../../helpers/MarginHelper'); const chai = require('chai'); const expect = chai.expect; chai.use(require('chai-bignumber')()); const BigNumber = require('bignumber.js'); +const { ZeroEx } = require('0x.js'); const Margin = artifacts.require('Margin'); const TokenA = artifacts.require('TokenA'); +const TestToken = artifacts.require('TestToken'); +const ZeroExProxy = artifacts.require('ZeroExProxy'); contract('Margin', accounts => { after(async () => { @@ -15,17 +18,33 @@ contract('Margin', accounts => { await snapshot(web3); }); - describe('TEST_POSITIONS', () => { - it('sets up test positions correctly', async () => { - await checkTestPositions(); + describe('seeds', () => { + context('positions', () => { + it('sets up seed positions correctly', async () => { + await checkSeedPositions(); + }); + + it('seed positions still exist after reset', async () => { + await checkSeedPositions(); + + await reset(web3); + + await checkSeedPositions(); + }); }); - it('test positions still exist after reset', async () => { - await checkTestPositions(); + context('orders', () => { + it('sets up seed orders correctly', async () => { + await checkSeedOrders(); + }); - await reset(web3); + it('seed orders still exist after reset', async () => { + await checkSeedOrders(); - await checkTestPositions(); + await reset(web3); + + await checkSeedOrders(); + }); }); }); @@ -73,23 +92,45 @@ contract('Margin', accounts => { }); }); -async function checkTestPositions() { - const promises = TEST_POSITIONS.map(async testPosition => { +async function checkSeedPositions() { + const promises = seeds.positions.map(async seedPosition => { const margin = await Margin.deployed(); - const position = await getPosition(margin, testPosition.id); - - expect(testPosition.owedToken).to.be.eq(position.owedToken); - expect(testPosition.heldToken).to.be.eq(position.heldToken); - expect(testPosition.lender).to.be.eq(position.lender); - expect(testPosition.owner).to.be.eq(position.owner); - expect(testPosition.interestRate).to.be.bignumber.eq(position.interestRate); - expect(testPosition.requiredDeposit).to.be.bignumber.eq(position.requiredDeposit); - expect(testPosition.callTimeLimit).to.be.bignumber.eq(position.callTimeLimit); - expect(testPosition.startTimestamp).to.be.bignumber.eq(position.startTimestamp); - expect(testPosition.callTimestamp).to.be.bignumber.eq(position.callTimestamp); - expect(testPosition.maxDuration).to.be.bignumber.eq(position.maxDuration); - expect(testPosition.interestPeriod).to.be.bignumber.eq(position.interestPeriod); + const position = await getPosition(margin, seedPosition.id); + + expect(seedPosition.owedToken).to.be.eq(position.owedToken); + expect(seedPosition.heldToken).to.be.eq(position.heldToken); + expect(seedPosition.lender).to.be.eq(position.lender); + expect(seedPosition.owner).to.be.eq(position.owner); + expect(seedPosition.interestRate).to.be.bignumber.eq(position.interestRate); + expect(seedPosition.requiredDeposit).to.be.bignumber.eq(position.requiredDeposit); + expect(seedPosition.callTimeLimit).to.be.bignumber.eq(position.callTimeLimit); + expect(seedPosition.startTimestamp).to.be.bignumber.eq(position.startTimestamp); + expect(seedPosition.callTimestamp).to.be.bignumber.eq(position.callTimestamp); + expect(seedPosition.maxDuration).to.be.bignumber.eq(position.maxDuration); + expect(seedPosition.interestPeriod).to.be.bignumber.eq(position.interestPeriod); + }); + + await Promise.all(promises); +} + +async function checkSeedOrders() { + const promises = seeds.orders.map(async seedOrder => { + expect(ZeroEx.isValidSignature( + ZeroEx.getOrderHashHex(seedOrder), + seedOrder.ecSignature, + seedOrder.maker + )).to.be.true; + + const makerToken = await TestToken.at(seedOrder.makerTokenAddress); + + const [makerBalance, makerAllowance] = await Promise.all([ + makerToken.balanceOf.call(seedOrder.maker), + makerToken.allowance.call(seedOrder.maker, ZeroExProxy.address), + ]); + + expect(makerBalance).to.be.bignumber.gte(seedOrder.makerTokenAmount); + expect(makerAllowance).to.be.bignumber.gte(seedOrder.makerTokenAmount); }); await Promise.all(promises);