From 6675efc68c3b5b082200e1dd63d42b3e0d3b7ecb Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Mar 2019 08:11:49 -0800 Subject: [PATCH] TEC Registry with tests --- contracts/tec/compiler.json | 2 +- .../src/registry/MixinTECRegistryCore.sol | 45 ++++++++++++ .../contracts/src/registry/TECRegistry.sol | 33 +++++++++ .../registry/interfaces/ITECRegistryCore.sol | 39 +++++++++++ contracts/tec/package.json | 2 +- contracts/tec/src/artifacts.ts | 2 + contracts/tec/src/wrappers.ts | 1 + contracts/tec/test/tec_registry.ts | 70 +++++++++++++++++++ .../tec/test/utils/tec_registry_wrapper.ts | 62 ++++++++++++++++ contracts/tec/tsconfig.json | 1 + 10 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 contracts/tec/contracts/src/registry/MixinTECRegistryCore.sol create mode 100644 contracts/tec/contracts/src/registry/TECRegistry.sol create mode 100644 contracts/tec/contracts/src/registry/interfaces/ITECRegistryCore.sol create mode 100644 contracts/tec/test/tec_registry.ts create mode 100644 contracts/tec/test/utils/tec_registry_wrapper.ts diff --git a/contracts/tec/compiler.json b/contracts/tec/compiler.json index 68d864c189..5b4ac3aa0b 100644 --- a/contracts/tec/compiler.json +++ b/contracts/tec/compiler.json @@ -16,5 +16,5 @@ } } }, - "contracts": ["src/TEC.sol", "test/TestLibs.sol", "test/TestMixins.sol"] + "contracts": ["src/TEC.sol", "src/registry/TECRegistry.sol", "test/TestLibs.sol", "test/TestMixins.sol"] } diff --git a/contracts/tec/contracts/src/registry/MixinTECRegistryCore.sol b/contracts/tec/contracts/src/registry/MixinTECRegistryCore.sol new file mode 100644 index 0000000000..255bbb79ec --- /dev/null +++ b/contracts/tec/contracts/src/registry/MixinTECRegistryCore.sol @@ -0,0 +1,45 @@ +/* + + Copyright 2018 ZeroEx Intl. + + 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. + +*/ + +pragma solidity 0.5.3; +pragma experimental ABIEncoderV2; + +import "./interfaces/ITECRegistryCore.sol"; + + +// solhint-disable no-empty-blocks +contract MixinTECRegistryCore is + ITECRegistryCore +{ + // mapping from `tecOperator` -> `tecEndpoint` + mapping (address => string) internal tecEndpoints; + + /// @dev Called by a TEC operator to set the endpoint of their TEC. + /// @param tecEndpoint endpoint of the TEC. + function setTecEndpoint(string calldata tecEndpoint) external { + address tecOperator = msg.sender; + tecEndpoints[tecOperator] = tecEndpoint; + emit TecEndpointSet(tecOperator, tecEndpoint); + } + + /// @dev Gets the endpoint for a TEC. + /// @param tecOperator operator of the TEC endpoint. + function getTecEndpoint(address tecOperator) external view returns (string memory tecEndpoint) { + return tecEndpoints[tecOperator]; + } +} diff --git a/contracts/tec/contracts/src/registry/TECRegistry.sol b/contracts/tec/contracts/src/registry/TECRegistry.sol new file mode 100644 index 0000000000..8bad7e4224 --- /dev/null +++ b/contracts/tec/contracts/src/registry/TECRegistry.sol @@ -0,0 +1,33 @@ +/* + + Copyright 2018 ZeroEx Intl. + + 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. + +*/ + +pragma solidity 0.5.3; +pragma experimental ABIEncoderV2; + +import "./MixinTECRegistryCore.sol"; + + +// solhint-disable no-empty-blocks +contract TECRegistry is + MixinTECRegistryCore +{ + constructor () + public + MixinTECRegistryCore() + {} +} diff --git a/contracts/tec/contracts/src/registry/interfaces/ITECRegistryCore.sol b/contracts/tec/contracts/src/registry/interfaces/ITECRegistryCore.sol new file mode 100644 index 0000000000..d1f56b6cc7 --- /dev/null +++ b/contracts/tec/contracts/src/registry/interfaces/ITECRegistryCore.sol @@ -0,0 +1,39 @@ +/* + + Copyright 2018 ZeroEx Intl. + + 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. + +*/ + +pragma solidity 0.5.3; +pragma experimental ABIEncoderV2; + + +// solhint-disable no-empty-blocks +contract ITECRegistryCore +{ + /// @dev Emitted when a TEC endpoint is set. + event TecEndpointSet( + address tecOperator, + string tecEndpoint + ); + + /// @dev Called by a TEC operator to set the endpoint of their TEC. + /// @param tecEndpoint endpoint of the TEC. + function setTecEndpoint(string calldata tecEndpoint) external; + + /// @dev Gets the endpoint for a TEC. + /// @param tecOperator operator of the TEC endpoint. + function getTecEndpoint(address tecOperator) external view returns (string memory tecEndpoint); +} diff --git a/contracts/tec/package.json b/contracts/tec/package.json index aa866922e8..621313b585 100644 --- a/contracts/tec/package.json +++ b/contracts/tec/package.json @@ -33,7 +33,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "./generated-artifacts/@(IExchange|TEC|TestLibs|TestMixins).json", + "abis": "./generated-artifacts/@(TEC|TECRegistry|TestLibs|TestMixins).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/tec/src/artifacts.ts b/contracts/tec/src/artifacts.ts index d37eb0fff3..8772e63af9 100644 --- a/contracts/tec/src/artifacts.ts +++ b/contracts/tec/src/artifacts.ts @@ -6,10 +6,12 @@ import { ContractArtifact } from 'ethereum-types'; import * as TEC from '../generated-artifacts/TEC.json'; +import * as TECRegistry from '../generated-artifacts/TECRegistry.json'; import * as TestLibs from '../generated-artifacts/TestLibs.json'; import * as TestMixins from '../generated-artifacts/TestMixins.json'; export const artifacts = { TEC: TEC as ContractArtifact, + TECRegistry: TECRegistry as ContractArtifact, TestLibs: TestLibs as ContractArtifact, TestMixins: TestMixins as ContractArtifact, }; diff --git a/contracts/tec/src/wrappers.ts b/contracts/tec/src/wrappers.ts index 69ad17bdfa..143e547e9d 100644 --- a/contracts/tec/src/wrappers.ts +++ b/contracts/tec/src/wrappers.ts @@ -3,6 +3,7 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../generated-wrappers/t_e_c_registry'; export * from '../generated-wrappers/tec'; export * from '../generated-wrappers/test_libs'; export * from '../generated-wrappers/test_mixins'; diff --git a/contracts/tec/test/tec_registry.ts b/contracts/tec/test/tec_registry.ts new file mode 100644 index 0000000000..921786c7db --- /dev/null +++ b/contracts/tec/test/tec_registry.ts @@ -0,0 +1,70 @@ +import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; +import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import * as chai from 'chai'; +import { LogWithDecodedArgs } from 'ethereum-types'; + +import { TECRegistryTecEndpointSetEventArgs } from '../src'; + +import { TECRegistryWrapper } from './utils/tec_registry_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); +// tslint:disable:no-unnecessary-type-assertion +describe('TEC Registry tests', () => { + let tecOperator: string; + const tecEndpoint = 'http://sometec.0x.org'; + const nilTecEndpoint = ''; + let tecRegistryWrapper: TECRegistryWrapper; + // tests + before(async () => { + await blockchainLifecycle.startAsync(); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + before(async () => { + // setup accounts (skip owner) + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + [, tecOperator] = accounts; + // deploy tec registry + tecRegistryWrapper = new TECRegistryWrapper(provider); + await tecRegistryWrapper.deployTecRegistryAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('core', () => { + it('Should successfully set a TEC endpoint', async () => { + await tecRegistryWrapper.setTecEndpointAsync(tecOperator, tecEndpoint); + const recordedTecEndpoint = await tecRegistryWrapper.getTecEndpointAsync(tecOperator); + expect(recordedTecEndpoint).to.be.equal(tecEndpoint); + }); + it('Should successfully unset a TEC endpoint', async () => { + // set TEC endpoint + await tecRegistryWrapper.setTecEndpointAsync(tecOperator, tecEndpoint); + let recordedTecEndpoint = await tecRegistryWrapper.getTecEndpointAsync(tecOperator); + expect(recordedTecEndpoint).to.be.equal(tecEndpoint); + // unset TEC endpoint + await tecRegistryWrapper.setTecEndpointAsync(tecOperator, nilTecEndpoint); + recordedTecEndpoint = await tecRegistryWrapper.getTecEndpointAsync(tecOperator); + expect(recordedTecEndpoint).to.be.equal(nilTecEndpoint); + }); + it('Should emit an event when setting TEC endpoint', async () => { + // set TEC endpoint + const txReceipt = await tecRegistryWrapper.setTecEndpointAsync(tecOperator, tecEndpoint); + const recordedTecEndpoint = await tecRegistryWrapper.getTecEndpointAsync(tecOperator); + expect(recordedTecEndpoint).to.be.equal(tecEndpoint); + // validate event + expect(txReceipt.logs.length).to.be.equal(1); + const log = txReceipt.logs[0] as LogWithDecodedArgs; + expect(log.args.tecOperator).to.be.equal(tecOperator); + expect(log.args.tecEndpoint).to.be.equal(tecEndpoint); + }); + }); +}); diff --git a/contracts/tec/test/utils/tec_registry_wrapper.ts b/contracts/tec/test/utils/tec_registry_wrapper.ts new file mode 100644 index 0000000000..6c51b4b48d --- /dev/null +++ b/contracts/tec/test/utils/tec_registry_wrapper.ts @@ -0,0 +1,62 @@ +import { LogDecoder, txDefaults } from '@0x/contracts-test-utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { artifacts, TECRegistryContract } from '../../src'; + +export class TECRegistryWrapper { + private readonly _web3Wrapper: Web3Wrapper; + private readonly _provider: ZeroExProvider; + private readonly _logDecoder: LogDecoder; + private _tecRegistryContract?: TECRegistryContract; + /** + * Instanitates an ERC20Wrapper + * @param provider Web3 provider to use for all JSON RPC requests + * @param tecOperatorAddresses Addresses of TEC operators + * @param contractOwnerAddress Desired owner of the contract + * Instance of ERC20Wrapper + */ + constructor(provider: ZeroExProvider) { + this._web3Wrapper = new Web3Wrapper(provider); + this._provider = provider; + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); + } + public async deployTecRegistryAsync(): Promise { + this._tecRegistryContract = await TECRegistryContract.deployFrom0xArtifactAsync( + artifacts.TECRegistry, + this._provider, + txDefaults, + ); + if (_.isUndefined(this._tecRegistryContract)) { + throw new Error(`Failed to deploy TEC Registry contract.`); + } + return this._tecRegistryContract; + } + public async setTecEndpointAsync( + tecOperator: string, + tecEndpoint: string, + ): Promise { + this._assertTECRegistryDeployed(); + const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( + await (this._tecRegistryContract as TECRegistryContract).setTecEndpoint.sendTransactionAsync(tecEndpoint, { + from: tecOperator, + }), + ); + return txReceipt; + } + public async getTecEndpointAsync(tecOperator: string): Promise { + this._assertTECRegistryDeployed(); + const tecEndpoint = await (this._tecRegistryContract as TECRegistryContract).getTecEndpoint.callAsync( + tecOperator, + ); + return tecEndpoint; + } + private _assertTECRegistryDeployed(): void { + if (_.isUndefined(this._tecRegistryContract)) { + throw new Error( + 'The TEC Registry contract was not deployed through the TECRegistryWrapper. Call `eployTecRegistryAsync` to deploy.', + ); + } + } +} diff --git a/contracts/tec/tsconfig.json b/contracts/tec/tsconfig.json index fc2b9eac21..8bab047f71 100644 --- a/contracts/tec/tsconfig.json +++ b/contracts/tec/tsconfig.json @@ -4,6 +4,7 @@ "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ "generated-artifacts/TEC.json", + "generated-artifacts/TECRegistry.json", "generated-artifacts/TestLibs.json", "generated-artifacts/TestMixins.json" ],