@gnosis.pm/pm-contracts
Version:
Collection of smart contracts for the Gnosis prediction market platform
641 lines (524 loc) • 28.4 kB
JavaScript
const _ = require('lodash')
const { wait } = require('./digix_tempo')(web3)
const BigNumber = require('bignumber.js')
const utils = require('./utils')
const { getBlock, getParamFromTxEvent, assertRejects, randrange, randnums } = utils
const CategoricalEvent = artifacts.require('CategoricalEvent')
const EventFactory = artifacts.require('EventFactory')
const OutcomeToken = artifacts.require('OutcomeToken')
const WETH9 = artifacts.require('WETH9')
const CentralizedOracle = artifacts.require('CentralizedOracle')
const CentralizedOracleFactory = artifacts.require('CentralizedOracleFactory')
const StandardMarket = artifacts.require('StandardMarket')
const StandardMarketFactory = artifacts.require('StandardMarketFactory')
const LMSRMarketMaker = artifacts.require('LMSRMarketMaker')
const Campaign = artifacts.require('Campaign')
const CampaignFactory = artifacts.require('CampaignFactory')
contract('StandardMarket', function (accounts) {
let centralizedOracleFactory
let eventFactory
let etherToken
let standardMarketFactory
let lmsrMarketMaker
let campaignFactory
let ipfsHash, centralizedOracle, event
const numOutcomes = 3
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
beforeEach(async () => {
centralizedOracleFactory = await CentralizedOracleFactory.deployed()
eventFactory = await EventFactory.deployed()
etherToken = await WETH9.deployed()
standardMarketFactory = await StandardMarketFactory.deployed()
lmsrMarketMaker = await LMSRMarketMaker.deployed.call()
campaignFactory = await CampaignFactory.deployed()
// create event
ipfsHash = web3.utils.utf8ToHex('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG')
centralizedOracle = await getParamFromTxEvent(
await centralizedOracleFactory.createCentralizedOracle(ipfsHash),
'centralizedOracle', CentralizedOracle
)
event = await getParamFromTxEvent(
await eventFactory.createCategoricalEvent(etherToken.address, centralizedOracle.address, numOutcomes),
'categoricalEvent', CategoricalEvent
)
})
it('can be created and closed', async () => {
// Create market
const buyer = 5
const feeFactor = 0
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[buyer] }),
'market', StandardMarket
)
// Fund market
const funding = 100
await etherToken.deposit({ value: funding, from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), funding)
await etherToken.approve(market.address, funding, { from: accounts[buyer] })
await market.fund(funding, { from: accounts[buyer] })
// StandardMarket can only be funded once
await etherToken.deposit({ value: funding, from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), funding)
await etherToken.approve(market.address, funding, { from: accounts[buyer] })
await assertRejects(market.fund(funding, { from: accounts[buyer] }), 'market funded twice')
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), funding)
// Close market
await market.close({ from: accounts[buyer] })
// StandardMarket can only be closed once
await assertRejects(market.close({ from: accounts[buyer] }), 'market closed twice')
// Sell all outcomes
await event.sellAllOutcomes(funding, { from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), funding * 2)
})
it('should allow buying and selling (legacy)', async () => {
// create market
const investor = 0
const feeFactor = 50000 // 5%
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[investor] }),
'market', StandardMarket
)
// Fund market
const funding = 1e18.toString()
await etherToken.deposit({ value: funding, from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), funding)
await etherToken.approve(market.address, funding, { from: accounts[investor] })
await market.fund(funding, { from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), 0)
// Buy outcome tokens
const buyer = 1
const outcome = 0
const tokenCount = 1e15
const outcomeTokenCost = await lmsrMarketMaker.calcCost.call(market.address, outcome, tokenCount)
let fee = await market.calcMarketFee.call(outcomeTokenCost)
assert.equal(fee, Math.floor(outcomeTokenCost * 5 / 100))
const cost = fee.add(outcomeTokenCost)
await etherToken.deposit({ value: cost, from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), cost.toString())
await etherToken.approve(market.address, cost, { from: accounts[buyer] })
assert.equal(await getParamFromTxEvent(
await market.buy(outcome, tokenCount, cost, { from: accounts[buyer] }), 'outcomeTokenCost'
), outcomeTokenCost.toString())
const outcomeToken = await OutcomeToken.at(await event.outcomeTokens.call(outcome))
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), tokenCount)
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), 0)
// Sell outcome tokens
const outcomeTokenProfit = await lmsrMarketMaker.calcProfit.call(market.address, outcome, tokenCount)
fee = await market.calcMarketFee.call(outcomeTokenProfit)
const profit = outcomeTokenProfit.sub(fee)
await outcomeToken.approve(market.address, tokenCount, { from: accounts[buyer] })
assert.equal(await getParamFromTxEvent(
await market.sell(outcome, tokenCount, profit, { from: accounts[buyer] }), 'outcomeTokenProfit'
).valueOf(), outcomeTokenProfit.toString())
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), 0)
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), profit.toString())
await etherToken.transfer(ZERO_ADDRESS, profit, { from: accounts[buyer] })
})
it('should allow short selling (legacy)', async () => {
// create market
const investor = 7
const feeFactor = 50000 // 5%
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[investor] }),
'market', StandardMarket
)
// Fund market
const funding = 1e18.toString()
await etherToken.deposit({ value: funding, from: accounts[investor] })
assert.equal((await etherToken.balanceOf.call(accounts[investor])).valueOf(), funding)
await etherToken.approve(market.address, funding, { from: accounts[investor] })
await market.fund(funding, { from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), 0)
// Short sell outcome tokens
const buyer = 7
const outcome = 0
const oppositeOutcome = 1
const tokenCount = 1e15
const outcomeTokenProfit = await lmsrMarketMaker.calcProfit.call(market.address, outcome, tokenCount)
const fee = await market.calcMarketFee.call(outcomeTokenProfit)
const cost = fee.add(web3.utils.toBN(tokenCount)).sub(outcomeTokenProfit)
await etherToken.deposit({ value: tokenCount, from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), tokenCount.toString())
await etherToken.approve(market.address, tokenCount.toString(), { from: accounts[buyer] })
assert.equal(
await getParamFromTxEvent(
await market.shortSell(outcome, tokenCount.toString(), outcomeTokenProfit - fee, { from: accounts[buyer] }),
'cost', null, 'OutcomeTokenShortSale'
).valueOf(), cost.toString())
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), (tokenCount - cost).toString())
await etherToken.transfer(ZERO_ADDRESS, (tokenCount - cost).toString(), { from: accounts[buyer] })
const outcomeToken = await OutcomeToken.at(await event.outcomeTokens.call(oppositeOutcome))
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), tokenCount.toString())
})
it('should be created by a successful campaign (legacy)', async () => {
// Create campaign
const feeFactor = 50000 // 5%
const funding = 1e18.toString()
const deadline = (await web3.eth.getBlock('latest')).timestamp + 60 // in 1h
const campaign = await Campaign.at(await getParamFromTxEvent(
await campaignFactory.createCampaign(
event.address,
standardMarketFactory.address,
lmsrMarketMaker.address,
feeFactor,
funding,
deadline), 'campaign'))
assert.equal(await campaign.stage.call(), 0)
// Fund campaign
const backer1 = 2
let amount = 7.5e17
await etherToken.deposit({ value: amount, from: accounts[backer1] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer1] })
await campaign.fund(amount.toString(), { from: accounts[backer1] })
assert.equal((await campaign.stage()).valueOf(), 0)
const backer2 = 3
amount = 2.5e17
await etherToken.deposit({ value: amount, from: accounts[backer2] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer2] })
campaign.fund(amount.toString(), { from: accounts[backer2] })
assert.equal(await campaign.stage.call(), 1)
// Create market
const market = await StandardMarket.at(await getParamFromTxEvent(await campaign.createMarket(), 'market'))
// Trade
const buyer = 4
const outcome = 0
const tokenCount = 1e15
const outcomeTokenCost = await lmsrMarketMaker.calcCost.call(market.address, outcome, tokenCount)
const fee = await market.calcMarketFee.call(outcomeTokenCost)
assert.equal(fee.valueOf(), new BigNumber(outcomeTokenCost).times(.05).integerValue(BigNumber.ROUND_FLOOR).toString())
const cost = outcomeTokenCost.add(fee)
await etherToken.deposit({ value: cost, from: accounts[buyer] })
assert.equal((await etherToken.balanceOf.call(accounts[buyer])).valueOf(), cost.toString())
await etherToken.approve(market.address, cost, { from: accounts[buyer] })
assert.equal(await getParamFromTxEvent(
await market.buy(outcome, tokenCount.toString(), cost, { from: accounts[buyer] }), 'outcomeTokenCost').valueOf()
, outcomeTokenCost.toString())
// Set outcome
await centralizedOracle.setOutcome(1)
await event.setOutcome()
// Withdraw fees
await campaign.closeMarket()
const finalBalance = await campaign.finalBalance()
assert(finalBalance.gt(funding))
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer1] }),
'fees'
).valueOf(), BigNumber(finalBalance).times(.75).integerValue(BigNumber.ROUND_FLOOR).toString())
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer2] }),
'fees'
).valueOf(), BigNumber(finalBalance).times(.25).integerValue(BigNumber.ROUND_FLOOR).toString())
// Withdraw works only once
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer1] }),
'fees'
).valueOf(), 0)
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer2] }),
'fees'
).valueOf(), 0)
})
it('should not be created by an unsuccessful campaign (legacy)', async () => {
// Create campaign
const feeFactor = 50000 // 5%
const funding = 1e18
const deadline = (await web3.eth.getBlock('latest')).timestamp + 60 // in 1h
const campaign = await Campaign.at(await getParamFromTxEvent(
await campaignFactory.createCampaign(
event.address,
standardMarketFactory.address,
lmsrMarketMaker.address,
feeFactor,
funding.toString(),
deadline), 'campaign'))
assert.equal(await campaign.stage.call(), 0)
// Fund campaign
const backer1 = 8
const amount = 7.5e17
await etherToken.deposit({ value: amount, from: accounts[backer1] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer1] })
await campaign.fund(amount.toString(), { from: accounts[backer1] })
assert.equal((await campaign.stage()).valueOf(), 0)
// Deadline passes
await wait(61)
assert.equal(
await getParamFromTxEvent(
await campaign.refund({ from: accounts[backer1] }), 'refund'),
amount)
assert.equal(
await getParamFromTxEvent(
await campaign.refund({ from: accounts[backer1] }), 'refund'),
0)
})
it('should allow buying and selling', async () => {
// create market
const investor = 0
const feeFactor = 50000 // 5%
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[investor] }),
'market', StandardMarket
)
// Fund market
const funding = 1e18
await etherToken.deposit({ value: funding, from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), funding.toString())
await etherToken.approve(market.address, funding.toString(), { from: accounts[investor] })
await market.fund(funding.toString(), { from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), 0)
// Buy outcome tokens
const buyer = 1
const outcome = 0
const tokenCount = 1e15
let outcomeTokenAmounts = Array.from({length: numOutcomes}, (v, i) => i === outcome ? tokenCount : 0)
const outcomeTokenCost = await lmsrMarketMaker.calcNetCost.call(market.address, outcomeTokenAmounts)
let fee = await market.calcMarketFee.call(outcomeTokenCost)
assert.equal(fee, Math.floor(outcomeTokenCost * 5 / 100))
const cost = fee.add(outcomeTokenCost)
await etherToken.deposit({ value: cost, from: accounts[buyer] })
assert.equal((await etherToken.balanceOf.call(accounts[buyer])).valueOf(), cost.toString())
await etherToken.approve(market.address, cost, { from: accounts[buyer] })
assert.equal(await getParamFromTxEvent(
await market.trade(outcomeTokenAmounts, cost, { from: accounts[buyer] }), 'outcomeTokenNetCost'
), outcomeTokenCost.toString())
const outcomeToken = await OutcomeToken.at(await event.outcomeTokens.call(outcome))
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), tokenCount.toString())
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), 0)
// Sell outcome tokens
outcomeTokenAmounts = Array.from({length: numOutcomes}, (v, i) => i === outcome ? -tokenCount : 0)
const outcomeTokenProfit = (await lmsrMarketMaker.calcNetCost.call(market.address, outcomeTokenAmounts)).neg()
fee = await market.calcMarketFee.call(outcomeTokenProfit)
const profit = outcomeTokenProfit.sub(fee)
await outcomeToken.approve(market.address, tokenCount.toString(), { from: accounts[buyer] })
assert.equal((await getParamFromTxEvent(
await market.trade(outcomeTokenAmounts, -profit, { from: accounts[buyer] }), 'outcomeTokenNetCost'
)).neg().valueOf(), outcomeTokenProfit.toString())
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), 0)
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), profit.toString())
})
it('should allow short selling', async () => {
// create market
const investor = 7
const feeFactor = 50000 // 5%
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[investor] }),
'market', StandardMarket
)
// Fund market
const funding = 1e18
await etherToken.deposit({ value: funding, from: accounts[investor] })
assert.equal((await etherToken.balanceOf.call(accounts[investor])).valueOf(), funding.toString())
await etherToken.approve(market.address, funding.toString(), { from: accounts[investor] })
await market.fund(funding.toString(), { from: accounts[investor] })
assert.equal(await etherToken.balanceOf.call(accounts[investor]), 0)
// Short sell outcome tokens
const buyer = 7
const outcome = 0
const differentOutcome = 1
const tokenCount = 1e15
const outcomeTokenAmounts = Array.from({length: numOutcomes}, (v, i) => i !== outcome ? tokenCount : 0)
const outcomeTokenCost = await lmsrMarketMaker.calcNetCost.call(market.address, outcomeTokenAmounts)
const fee = await market.calcMarketFee.call(outcomeTokenCost)
const cost = outcomeTokenCost.add(fee)
await etherToken.deposit({ value: cost, from: accounts[buyer] })
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), cost.toString())
await etherToken.approve(market.address, cost, { from: accounts[buyer] })
assert.equal(
await getParamFromTxEvent(
await market.trade(outcomeTokenAmounts, cost, { from: accounts[buyer] }),
'outcomeTokenNetCost'
).valueOf(), outcomeTokenCost.toString())
assert.equal(await etherToken.balanceOf.call(accounts[buyer]), 0)
const outcomeToken = await OutcomeToken.at(await event.outcomeTokens.call(differentOutcome))
assert.equal(await outcomeToken.balanceOf.call(accounts[buyer]), tokenCount)
})
it('should be created by a successful campaign', async () => {
// Create campaign
const feeFactor = 50000 // 5%
const funding = 1e18
const deadline = (await getBlock('latest')).timestamp + 60 // in 1h
const campaign = await Campaign.at(await getParamFromTxEvent(
await campaignFactory.createCampaign(
event.address,
standardMarketFactory.address,
lmsrMarketMaker.address,
feeFactor,
funding.toString(),
deadline), 'campaign'))
assert.equal(await campaign.stage.call(), 0)
// Fund campaign
const backer1 = 2
let amount = 7.5e17
await etherToken.deposit({ value: amount, from: accounts[backer1] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer1] })
await campaign.fund(amount.toString(), { from: accounts[backer1] })
assert.equal((await campaign.stage()).valueOf(), 0)
const backer2 = 3
amount = 2.5e17
await etherToken.deposit({ value: amount, from: accounts[backer2] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer2] })
campaign.fund(amount.toString(), { from: accounts[backer2] })
assert.equal(await campaign.stage.call(), 1)
// Create market
const market = await StandardMarket.at(await getParamFromTxEvent(await campaign.createMarket(), 'market'))
// Trade
const buyer = 4
const outcome = 0
const tokenCount = 1e15
const outcomeTokenAmounts = Array.from({length: numOutcomes}, (v, i) => i === outcome ? tokenCount : 0)
const outcomeTokenCost = await lmsrMarketMaker.calcNetCost.call(market.address, outcomeTokenAmounts)
const fee = await market.calcMarketFee.call(outcomeTokenCost)
assert.equal(fee.valueOf(), new BigNumber(outcomeTokenCost).times(.05).integerValue(BigNumber.ROUND_FLOOR).toString())
const cost = outcomeTokenCost.add(fee)
await etherToken.deposit({ value: cost, from: accounts[buyer] })
assert.equal((await etherToken.balanceOf.call(accounts[buyer])).valueOf(), cost.toString())
await etherToken.approve(market.address, cost, { from: accounts[buyer] })
assert.equal(await getParamFromTxEvent(
await market.trade(outcomeTokenAmounts, cost, { from: accounts[buyer] }), 'outcomeTokenNetCost').valueOf()
, outcomeTokenCost.toString())
// Set outcome
await centralizedOracle.setOutcome(1)
await event.setOutcome()
// Withdraw fees
await campaign.closeMarket()
const finalBalance = await campaign.finalBalance()
assert(finalBalance.gt(funding))
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer1] }),
'fees'
).valueOf(), new BigNumber(finalBalance).times(.75).integerValue(BigNumber.ROUND_FLOOR).toString())
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer2] }),
'fees'
).valueOf(), new BigNumber(finalBalance).times(.25).integerValue(BigNumber.ROUND_FLOOR).toString())
// Withdraw works only once
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer1] }),
'fees'
).valueOf(), 0)
assert.equal(
await getParamFromTxEvent(
await campaign.withdrawFees({ from: accounts[backer2] }),
'fees'
).valueOf(), 0)
})
it('should not be created by an unsuccessful campaign', async () => {
// Create campaign
const feeFactor = 50000 // 5%
const funding = 1e18
const deadline = (await getBlock('latest')).timestamp + 60 // in 1h
const campaign = await Campaign.at(await getParamFromTxEvent(
await campaignFactory.createCampaign(
event.address,
standardMarketFactory.address,
lmsrMarketMaker.address,
feeFactor,
funding.toString(),
deadline), 'campaign'))
assert.equal(await campaign.stage.call(), 0)
// Fund campaign
const backer1 = 8
const amount = 7.5e17
await etherToken.deposit({ value: amount, from: accounts[backer1] })
await etherToken.approve(campaign.address, amount.toString(), { from: accounts[backer1] })
await campaign.fund(amount.toString(), { from: accounts[backer1] })
assert.equal((await campaign.stage()).valueOf(), 0)
// Deadline passes
await wait(61)
assert.equal(
await getParamFromTxEvent(
await campaign.refund({ from: accounts[backer1] }), 'refund'),
amount.toString())
assert.equal(
await getParamFromTxEvent(
await campaign.refund({ from: accounts[backer1] }), 'refund'),
0)
})
it('trading stress testing', async () => {
const MAX_VALUE = web3.utils.toBN(new BigNumber(2).pow(256).minus(1))
const trader = 9
const feeFactor = 0
const market = await getParamFromTxEvent(
await standardMarketFactory.createMarket(event.address, lmsrMarketMaker.address, feeFactor, { from: accounts[trader] }),
'market', StandardMarket
)
// Get ready for trading
await etherToken.deposit({ value: 2e19, from: accounts[trader] })
await etherToken.approve(event.address, 1e19.toString(), { from: accounts[trader] })
await event.buyAllOutcomes(1e19.toString(), { from: accounts[trader] })
// Allow all trading
const outcomeTokens = await Promise.all((await Promise.all(
_.range(numOutcomes).map(i => event.outcomeTokens.call(i))
)).map(OutcomeToken.at))
await etherToken.approve(market.address, MAX_VALUE.toString(), { from: accounts[trader] })
await Promise.all(outcomeTokens.map(outcomeToken =>
outcomeToken.approve(market.address, MAX_VALUE.toString(), { from: accounts[trader] })))
// Fund market
const funding = 1e16
await market.fund(funding.toString(), { from: accounts[trader] })
for(let i = 0; i < 10; i++) {
const outcome = Math.floor(numOutcomes * Math.random())
const tokenCount = randrange(0, 1e16).valueOf()
const outcomeTokenAmounts = randnums(-1e16, 1e16, numOutcomes).map(n => n.valueOf())
const randParam = Math.random()
const [method, forWhat] = randParam < (1/3) ? ['buy', 'Cost'] :
randParam < (2/3) ? ['sell', 'Profit'] :
['trade', 'NetCost']
const limit = await lmsrMarketMaker['calc' + forWhat]
.call(...(method == 'trade' ?
[market.address, outcomeTokenAmounts]
: [market.address, outcome, tokenCount]))
const marketOutcomeTokenCounts = await Promise.all(outcomeTokens.map(outcomeToken =>
outcomeToken.balanceOf.call(market.address)))
const marketCollateralTokenCount = await etherToken.balanceOf.call(market.address)
if(method == 'buy') {
const marketOutcomeTokenCount = marketOutcomeTokenCounts[outcome]
assert(marketOutcomeTokenCount.add(limit).gte(tokenCount),
`trade ${i}: ${marketOutcomeTokenCount} + ${limit} < ${tokenCount}`)
} else if(method == 'sell') {
const newAmounts = marketOutcomeTokenCounts.slice()
newAmounts[outcome] = BigNumber(newAmounts[outcome]).plus(tokenCount)
const marketOutcomeSetAmount = BigNumber.min.apply(0, newAmounts)
assert(marketOutcomeSetAmount.plus(marketCollateralTokenCount).gte(limit),
`trade ${i}: ${marketOutcomeSetAmount} + ${marketCollateralTokenCount} < ${limit}`)
}
let txResult;
try {
if(method == 'trade')
txResult = await market[method](outcomeTokenAmounts, limit, { from: accounts[trader] })
else
txResult = await market[method](outcome, tokenCount, limit, { from: accounts[trader] })
} catch(e) {
throw new Error(`trade ${ i } (a ${
method
} of ${
method == 'trade' ?
outcomeTokenAmounts
: `${
tokenCount
} of outcome ${
outcome
}`
} with limit ${
limit
}) failed while market has:\n\n${
marketOutcomeTokenCounts.map(c => c.valueOf()).join('\n')
}\n\nand ${
marketCollateralTokenCount.valueOf()
}: ${
e.message
}`)
}
if(txResult)
assert.equal(
await getParamFromTxEvent(txResult, 'outcomeToken' + forWhat).valueOf(),
limit.toString())
}
})
})