Skip to content

Commit

Permalink
Merge branch 'dev' into new/energy/split-load
Browse files Browse the repository at this point in the history
  • Loading branch information
alcueca committed Jan 10, 2020
2 parents 1368822 + 3840533 commit 89b0957
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 227 deletions.
File renamed without changes.
35 changes: 35 additions & 0 deletions contracts/drafts/lists/README-OrderedList.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Lists

This is an Ethereum project that implements an ordered doubly linked list (https://en.wikipedia.org/wiki/Linked_list).

# Terminology
Object: Objects are linked to each other and together they are a Linked List
Head: The first object in the list. No other object points to the head.
Tail: The last object in the list. The tail points to no other object.
Data: In this contract the data is an Ethereum address, which can be used for any purpose.

# Implementation
Solidity doesn't support recursive type references, as in:
```
struct Object {
Object nextObject;
}
```
This renders a traditional implementation of Linked Lists impossible. In this implementation all Objects are given an id and stored in a mapping instead. This results in an extra inefficiency of doing an extra mapping lookup when following a link between objects.

## Usage

`OrderedList.sol`: Doubly Linked List, sorted by `rank` descending from the head.
* constructor: Creates an empty list.
* `function get(uint256 _id)`: Retrieves the Object denoted by `_id`.
* `function findRank(uint256 _rank)`: Return the id of the first Object with a lower or equal `_rank`, starting from the head.
* `function insert(uint256 _rank, address _data)`: Insert a new Object immediately before the one with the closest lower `_rank`.
* `function remove(uint256 _id)`: Remove the Object denoted by `_id` from the List.
* `function _addHead(address _data)`: Insert a new Object as the new Head with `_data` in the data field.
* `function _addTail(address _data)`: Insert a new Object as the new Tail with `_data` in the data field.
* `function _insertAfter(uint256 _prevId, address _data)`: Insert a new Object after the Object denoted by `_id` with `_data` in the data field.
* `function _insertBefore(uint256 _nextId, address _data)`: Insert a new Object before the Object denoted by `_id` with `_data` in the data field.
* `function _setHead(uint256 _id)`: Internal function to update the Head pointer.
* `function _createObject(address _data)`: Internal function to create an unlinked Object.
* `function _link(uint256 _prevId, uint256 _nextId)`: Internal function to link an Object to another.

File renamed without changes.
14 changes: 0 additions & 14 deletions contracts/lists/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,3 @@ This renders a traditional implementation of Linked Lists impossible. In this im
* `function _createObject(address _data)`: Internal function to create an unlinked Object.
* `function _link(uint256 _prevId, uint256 _nextId)`: Internal function to link an Object to another.

`OrderedList.sol`: Doubly Linked List, sorted by `rank` descending from the head.
* constructor: Creates an empty list.
* `function get(uint256 _id)`: Retrieves the Object denoted by `_id`.
* `function findRank(uint256 _rank)`: Return the id of the first Object with a lower or equal `_rank`, starting from the head.
* `function insert(uint256 _rank, address _data)`: Insert a new Object immediately before the one with the closest lower `_rank`.
* `function remove(uint256 _id)`: Remove the Object denoted by `_id` from the List.
* `function _addHead(address _data)`: Insert a new Object as the new Head with `_data` in the data field.
* `function _addTail(address _data)`: Insert a new Object as the new Tail with `_data` in the data field.
* `function _insertAfter(uint256 _prevId, address _data)`: Insert a new Object after the Object denoted by `_id` with `_data` in the data field.
* `function _insertBefore(uint256 _nextId, address _data)`: Insert a new Object before the Object denoted by `_id` with `_data` in the data field.
* `function _setHead(uint256 _id)`: Internal function to update the Head pointer.
* `function _createObject(address _data)`: Internal function to create an unlinked Object.
* `function _link(uint256 _prevId, uint256 _nextId)`: Internal function to link an Object to another.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@
"@types/bignumber.js": "5.0.0",
"@types/chai": "4.2.7",
"@types/mocha": "5.2.7",
"@types/node": "13.1.4",
"@types/node": "13.1.6",
"bignumber.js": "9.0.0",
"chai": "4.2.0",
"chai-bn": "0.2.0",
"coveralls": "3.0.9",
"cross-env": "6.0.3",
"directory-tree": "2.2.4",
Expand All @@ -61,11 +62,11 @@
"node-emoji": "1.10.0",
"pdf-from-html": "0.1.1",
"soldoc": "0.1.2-beta.6",
"solidity-coverage": "0.7.0",
"solidity-coverage": "0.7.1",
"truffle": "5.1.7",
"truffle-typings": "1.0.8",
"ts-generator": "0.0.8",
"ts-node": "8.5.4",
"ts-node": "8.6.0",
"tslint": "5.20.1",
"typechain": "1.0.3",
"typechain-target-truffle": "1.0.2",
Expand Down
113 changes: 65 additions & 48 deletions test/drafts/exchange/UniswapExchange.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import BigNumber from 'bignumber.js';
import chai = require('chai');
// tslint:disable-next-line:no-var-requires
const { balance, BN, constants, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers');
import { TestERC20MintableInstance } from '../../../types/truffle-contracts';
import { UniswapExchangeInstance, UniswapFactoryInstance } from '../../../types/truffle-contracts';

Expand All @@ -8,14 +10,9 @@ const UniswapExchange = artifacts.require('./exchange/UniswapExchange.sol') as T
const UniswapFactory = artifacts.require('./exchange/UniswapFactory.sol') as Truffle.Contract<UniswapFactoryInstance>;
// tslint:enable:max-line-length

// tslint:disable:no-var-requires
const chai = require('chai');
const girino = require('girino');
// tslint:enable:no-var-requires

const { expect } = chai;

chai.use(girino);
// tslint:disable-next-line:no-var-requires
chai.use(require('chai-bn')(require('bn.js')));
chai.should();

/** @test {UniswapExchange} contract */
contract('UniswapExchange - Initialization', (accounts) => {
Expand All @@ -34,14 +31,14 @@ contract('UniswapExchange - Initialization', (accounts) => {
uniswapExchange = await UniswapExchange.at(
(await uniswapFactory.launchExchange(token.address)).logs[0].args.exchange,
);
await token.mint(initialiser1, new BigNumber(1e18));
await token.approve(uniswapExchange.address, new BigNumber(1e18), { from: initialiser1 });
await token.mint(initialiser1, ether('1'));
await token.approve(uniswapExchange.address, ether('1'), { from: initialiser1 });
await uniswapExchange.initializeExchange.sendTransaction(
new BigNumber(1e18),
{ from: initialiser1, value: (new BigNumber(1e18)).toString() },
ether('1'),
{ from: initialiser1, value: ether('1').toString() },
);
assert.equal((await token.balanceOf(uniswapExchange.address)).toString(), (new BigNumber(1e18)).toString(), 'Token amount not transferred correctly.');
assert.equal((await web3.eth.getBalance(uniswapExchange.address)).toString(), (new BigNumber(1e18)).toString(), 'Ether not transferred correctly.');
(await web3.eth.getBalance(uniswapExchange.address)).should.be.bignumber.equal(ether('1'));
new BN((await token.balanceOf(uniswapExchange.address)).toString()).should.be.bignumber.equal(ether('1'));
});
});

Expand All @@ -61,11 +58,11 @@ contract('UniswapExchange - Trades', (accounts) => {
uniswapExchange = await UniswapExchange.at(
(await uniswapFactory.launchExchange(token.address)).logs[0].args.exchange,
);
await token.mint(initialiser1, new BigNumber(1e18));
await token.approve(uniswapExchange.address, new BigNumber(1e18), { from: initialiser1 });
await token.mint(initialiser1, ether('1'));
await token.approve(uniswapExchange.address, ether('1'), { from: initialiser1 });
await uniswapExchange.initializeExchange.sendTransaction(
new BigNumber(1e18),
{ from: initialiser1, value: (new BigNumber(1e18)).toString() },
ether('1'),
{ from: initialiser1, value: ether('1').toString() },
);
});

Expand All @@ -74,19 +71,19 @@ contract('UniswapExchange - Trades', (accounts) => {
*/
it('Ether to token swap', async () => {
const timeout = Math.floor((new Date().getTime()) / 1000) + 3600;
const minTokens = new BigNumber(3e17);
expect(
uniswapExchange.ethToTokenSwap.sendTransaction(
const minTokens = new BN('3e17');
expectEvent(
await uniswapExchange.ethToTokenSwap.sendTransaction(
minTokens,
timeout,
{ from: swapper, value: (new BigNumber(5e17)).toString() },
{ from: swapper, value: (new BN('5e17')).toString() },
),
).to.emit(
'EthToTokenPurchase',
).withArgs(
swapper,
(new BigNumber(5e17)).toString(),
(await token.balanceOf(swapper)),
{
buyer: swapper,
ethIn: new BN('5e17'),
tokensOut: await token.balanceOf(swapper),
},
);
});

Expand All @@ -95,12 +92,19 @@ contract('UniswapExchange - Trades', (accounts) => {
*/
it('Token to ether swap', async () => {
const timeout = Math.floor((new Date().getTime()) / 1000) + 3600;
const tokenAmount = new BigNumber(5e17);
const minEth = new BigNumber(3e17);
const tokenAmount = ether('0.5');
const minEth = ether('0.3');
token.mint(swapper, tokenAmount);
token.approve(uniswapExchange.address, tokenAmount, { from: swapper });
const balanceBefore = await web3.eth.getBalance(swapper);
expect(uniswapExchange.tokenToEthSwap(tokenAmount, minEth, timeout, { from: swapper })).to.emit('TokenToEthPurchase');
const swap = await uniswapExchange.tokenToEthSwap(tokenAmount, minEth, timeout, { from: swapper });
expectEvent(
swap,
'TokenToEthPurchase',
{
buyer: swapper,
tokensIn: tokenAmount,
},
);
});

/**
Expand All @@ -112,27 +116,40 @@ contract('UniswapExchange - Trades', (accounts) => {
const uniswapExchange2 = await UniswapExchange.at(
(await uniswapFactory.launchExchange(token2.address)).logs[0].args.exchange,
);
await token2.mint(initialiser2, new BigNumber(1e18));
await token2.approve(uniswapExchange2.address, new BigNumber(1e18), { from: initialiser2 });
await token2.mint(initialiser2, ether('1'));
await token2.approve(uniswapExchange2.address, ether('1'), { from: initialiser2 });
await uniswapExchange2.initializeExchange.sendTransaction(
new BigNumber(1e18),
{ from: initialiser2, value: (new BigNumber(1e18)).toString() },
ether('1'),
{ from: initialiser2, value: (ether('1')).toString() },
);
// Swap tokens
const timeout = Math.floor((new Date().getTime()) / 1000) + 3600;
const tokenAmount = new BigNumber(5e17);
const minEth = new BigNumber(2e17);
const tokenAmount = ether('0.5');
const minEth = ether('0.2');
token.mint(swapper, tokenAmount);
token.approve(uniswapExchange.address, tokenAmount, { from: swapper });
expect(
uniswapExchange.tokenToTokenSwap(
token2.address,
tokenAmount,
minEth,
timeout,
{ from: swapper },
),
).to.emit('TokenToEthPurchase').to.emit('EthToTokenPurchase');
const swap = await uniswapExchange.tokenToTokenSwap(
token2.address,
tokenAmount,
minEth,
timeout,
{ from: swapper },
);
expectEvent(
swap,
'TokenToEthPurchase',
{
buyer: swapper,
tokensIn: tokenAmount,
},
);
expectEvent(
swap,
'EthToTokenPurchase',
{
buyer: uniswapExchange.address,
tokensOut: await token2.balanceOf(swapper),
},
);
});
});

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { should } from 'chai';
import { OrderedListMockInstance } from '../../types/truffle-contracts';
import { OrderedListMockInstance } from '../../../types/truffle-contracts';

const OrderedList = artifacts
.require('./lists/mocks/OrderedListMock.sol') as Truffle.Contract<OrderedListMockInstance>;
.require('./drafts/lists/mocks/OrderedListMock.sol') as Truffle.Contract<OrderedListMockInstance>;
should();

const emptyData = '0x0000000000000000000000000000000000000000';
Expand Down
Loading

0 comments on commit 89b0957

Please sign in to comment.