Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement sortHash and sort on AddressArrayUtils #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/artifacts/ts
/build
/dist
/node_modules
/transpiled
/types/generated/*
coverage.json
Expand Down Expand Up @@ -31,4 +32,4 @@ yarn-error.log*
blockchain/

# Outputs
deployments/outputs.ts
deployments/outputs.ts
19 changes: 19 additions & 0 deletions contracts/lib/AddressArrayUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,23 @@ library AddressArrayUtils {
}
return true;
}

/**
* Naive implementation of sort
* @return Returns a sorted array
*/
function sort(address[] memory A) internal pure returns (address[] memory) {
uint256 length = A.length;
address[] memory newAddresses = A;
for (uint256 i = 0; i < length; i++) {
for (uint256 j = i + 1; j < length; j++) {
if (newAddresses[i] > newAddresses[j]) {
address temp = newAddresses[i];
newAddresses[i] = newAddresses[j];
newAddresses[j] = temp;
}
}
}
return newAddresses;
}
}
17 changes: 17 additions & 0 deletions contracts/lib/HashUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity 0.5.7;

import { AddressArrayUtils } from "./AddressArrayUtils.sol";


library HashUtils {
using AddressArrayUtils for address[];

/**
* Sorts the address array and hashes it using the keccak256 hashing algorithm.
* @param a The input array
* @return Returns bytes32 hash
*/
function sortHash(address[] memory a) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(a.sort()));
}
}
12 changes: 12 additions & 0 deletions contracts/mocks/ArrayAddressUtilsMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity 0.5.7;

import { AddressArrayUtils } from "../lib/AddressArrayUtils.sol";


contract AddressArrayUtilsMock {
using AddressArrayUtils for address[];

function testSort(address[] calldata _addressArray) external pure returns(address[] memory) {
return _addressArray.sort();
}
}
10 changes: 10 additions & 0 deletions contracts/mocks/HashUtilsMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pragma solidity 0.5.7;

import { HashUtils } from "../lib/HashUtils.sol";


contract HashUtilsMock {
function testSortHash(address[] calldata _addressArray) external pure returns(bytes32) {
return HashUtils.sortHash(_addressArray);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "set-protocol-contract-utils",
"version": "1.0.2",
"version": "1.0.3",
"main": "dist/artifacts/index.js",
"typings": "dist/typings/artifacts/index.d.ts",
"files": [
Expand Down
63 changes: 63 additions & 0 deletions test/contracts/lib/addressArrayUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require('module-alias/register');

import * as _ from 'lodash';
import * as chai from 'chai';
import { Address } from 'set-protocol-utils';


import ChaiSetup from '@utils/chaiSetup';
import { BigNumberSetup } from '@utils/bigNumberSetup';
import { AddressArrayUtilsMockContract } from '@utils/contracts';

import { LibraryMockHelper } from '@utils/helpers/libraryMockHelper';

BigNumberSetup.configure();
ChaiSetup.configure();
const { expect } = chai;


contract('AddressArrayUtils', accounts => {
const [ownerAccount] = accounts;
const libraryMockHelper = new LibraryMockHelper(ownerAccount);

let addressArrayUtils: AddressArrayUtilsMockContract;

beforeEach(async () => {
addressArrayUtils = await libraryMockHelper.deployAddressArrayUtilsMockAsync();
});

describe('#testSort', async () => {
let subjectToSort: Address[];

beforeEach(async () => {
subjectToSort = [
'0x6Ecbe1DB9EF729CBe972C83Fb886247691Fb6beb',
'0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84',
'0x5409ED021D9299bf6814279A6A1411A7e866A631',
];
});

async function subject(): Promise<string[]> {
return addressArrayUtils.testSort.callAsync(subjectToSort);
}

it('returns the sorted items', async () => {
const sortedResult = await subject();

const expectedResult = _.sortBy(subjectToSort);

expect(JSON.stringify(sortedResult)).to.equal(JSON.stringify(expectedResult));
});

describe('when the input is empty', async () => {
beforeEach(async () => {
subjectToSort = [];
});

it('returns an empty array', async () => {
const sortedResult = await subject();
expect(JSON.stringify(sortedResult)).to.equal(JSON.stringify([]));
});
});
});
});
52 changes: 52 additions & 0 deletions test/contracts/lib/hashUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require('module-alias/register');

import * as _ from 'lodash';
import * as chai from 'chai';
import { Address } from 'set-protocol-utils';


import ChaiSetup from '@utils/chaiSetup';
import { BigNumberSetup } from '@utils/bigNumberSetup';
import { HashUtilsMockContract } from '@utils/contracts';
import { getWeb3 } from '@utils/web3Helper';

import { LibraryMockHelper } from '@utils/helpers/libraryMockHelper';

BigNumberSetup.configure();
ChaiSetup.configure();
const { expect } = chai;
const web3 = getWeb3();

contract('HashUtils', accounts => {
const [ownerAccount] = accounts;
const libraryMockHelper = new LibraryMockHelper(ownerAccount);

let hashUtils: HashUtilsMockContract;

beforeEach(async () => {
hashUtils = await libraryMockHelper.deployHashUtilsMockAsync();
});

describe('#testSortHash', async () => {
let subjectAddressArray: Address[];

beforeEach(async () => {
subjectAddressArray = [
'0xE36Ea790bc9d7AB70C55260C66D52b1eca985f84',
'0x5409ED021D9299bf6814279A6A1411A7e866A631',
];
});

async function subject(): Promise<string> {
return hashUtils.testSortHash.callAsync(subjectAddressArray);
}

it('returns the correct hash', async () => {
const result = await subject();

const sorted = _.sortBy(subjectAddressArray);
const expected = web3.utils.soliditySha3({ t: 'address', v: sorted });
expect(JSON.stringify(result)).to.equal(JSON.stringify(expected));
});
});
});
2 changes: 2 additions & 0 deletions utils/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { AddressArrayUtilsMockContract } from '../types/generated/address_array_utils_mock';
export { BaseContract } from '../types/base_contract';
export { BoundsLibraryMockContract } from '../types/generated/bounds_library_mock';
export { AddressToAddressWhiteListContract } from '../types/generated/address_to_address_white_list';
Expand All @@ -7,6 +8,7 @@ export { Bytes32LibraryMockContract } from '../types/generated/bytes32_library_m
export { CommonMathMockContract } from '../types/generated/common_math_mock';
export { CommonValidationsLibraryMockContract } from '../types/generated/common_validations_library_mock';
export { CompoundUtilsMockContract } from '../types/generated/compound_utils_mock';
export { HashUtilsMockContract } from '../types/generated/hash_utils_mock';
export { LimitOneUpgradeMockContract } from '../types/generated/limit_one_upgrade_mock';
export { OracleWhiteListContract } from '../types/generated/oracle_white_list';
export { ScaleValidationsMockContract } from '../types/generated/scale_validations_mock';
Expand Down
23 changes: 23 additions & 0 deletions utils/helpers/libraryMockHelper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Address } from 'set-protocol-utils';
import * as _ from 'lodash';
import {
AddressArrayUtilsMockContract,
BoundsLibraryMockContract,
Bytes32LibraryMockContract,
CommonValidationsLibraryMockContract,
CommonMathMockContract,
CompoundUtilsMockContract,
HashUtilsMockContract,
ScaleValidationsMockContract
} from '../contracts';
import { BigNumber } from 'bignumber.js';
Expand All @@ -17,13 +19,15 @@ import {
} from '../web3Helper';
import { ZERO } from '../constants';

const AddressArrayUtilsMock = importArtifactsFromSource('AddressArrayUtilsMock');
const BoundsLibraryMock = importArtifactsFromSource('BoundsLibraryMock');
const Bytes32Library = importArtifactsFromSource('Bytes32Library');
const Bytes32LibraryMock = importArtifactsFromSource('Bytes32LibraryMock');
const CommonMathMock = importArtifactsFromSource('CommonMathMock');
const CommonValidationsLibrary = importArtifactsFromSource('CommonValidationsLibrary');
const CommonValidationsLibraryMock = importArtifactsFromSource('CommonValidationsLibraryMock');
const CompoundUtilsMock = importArtifactsFromSource('CompoundUtilsMock');
const HashUtilsMock = importArtifactsFromSource('HashUtilsMock');
const ScaleValidationsMock = importArtifactsFromSource('ScaleValidationsMock');


Expand All @@ -36,6 +40,17 @@ export class LibraryMockHelper {

/* ============ Deployment ============ */

public async deployAddressArrayUtilsMockAsync(
from: Address = this._contractOwnerAddress
): Promise<AddressArrayUtilsMockContract> {
const addressArrayUtils = await AddressArrayUtilsMock.new(txnFrom(from));

return new AddressArrayUtilsMockContract(
getContractInstance(addressArrayUtils),
txnFrom(from),
);
}

public async deployCommonValidationsLibraryAsync(
from: Address = this._contractOwnerAddress
): Promise<CommonValidationsLibraryMockContract> {
Expand Down Expand Up @@ -85,6 +100,14 @@ export class LibraryMockHelper {
return new ScaleValidationsMockContract(getContractInstance(scaleValidationsMockContract), txnFrom(from));
}

public async deployHashUtilsMockAsync(
from: Address = this._contractOwnerAddress
): Promise<HashUtilsMockContract> {
const hashUtilsMockContract = await HashUtilsMock.new(txnFrom(from));

return new HashUtilsMockContract(getContractInstance(hashUtilsMockContract), txnFrom(from));
}

public async deployBoundsLibraryMockAsync(
minBound: BigNumber,
maxBound: BigNumber,
Expand Down