@0x:contracts-utils Added a Refundable contract

This commit is contained in:
Alex Towle
2019-08-21 13:29:50 -07:00
parent a9857fa298
commit 365cb161cf
7 changed files with 196 additions and 1 deletions

View File

@@ -0,0 +1,36 @@
/*
Copyright 2019 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.9;
contract Refundable {
// This bool is used by the refund modifier to allow for lazily evaluated refunds.
bool internal shouldNotRefund;
modifier refund {
if (shouldNotRefund) {
_;
} else {
shouldNotRefund = true;
_;
msg.sender.transfer(address(this).balance);
}
}
}

View File

@@ -0,0 +1,66 @@
/*
Copyright 2019 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.9;
import "../src/Refundable.sol";
contract TestRefundable is
Refundable
{
uint256 public counter = 2;
function setCounter(uint256 newCounter)
external
{
counter = newCounter;
}
function complexReentrantRefundFunction()
external
payable
refund()
{
if (counter == 0) {
// This call tests lazy evaluation across different functions with the refund modifier
this.simpleRefundFunction();
} else {
counter--;
this.complexReentrantRefundFunction();
}
}
function simpleReentrantRefundFunction()
external
payable
refund()
{
if (counter != 0) {
counter--;
this.simpleReentrantRefundFunction();
}
}
function simpleRefundFunction()
external
payable
refund()
{} // solhint-disable-line no-empty-blocks
}

View File

@@ -35,7 +35,7 @@
"compile:truffle": "truffle compile"
},
"config": {
"abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|SafeMath|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestSafeMath).json",
"abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|SafeMath|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestSafeMath).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {

View File

@@ -23,6 +23,7 @@ import * as LibSafeMath from '../generated-artifacts/LibSafeMath.json';
import * as LibSafeMathRichErrors from '../generated-artifacts/LibSafeMathRichErrors.json';
import * as Ownable from '../generated-artifacts/Ownable.json';
import * as ReentrancyGuard from '../generated-artifacts/ReentrancyGuard.json';
import * as Refundable from '../generated-artifacts/Refundable.json';
import * as SafeMath from '../generated-artifacts/SafeMath.json';
import * as TestLibAddress from '../generated-artifacts/TestLibAddress.json';
import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json';
@@ -33,6 +34,7 @@ import * as TestLogDecoding from '../generated-artifacts/TestLogDecoding.json';
import * as TestLogDecodingDownstream from '../generated-artifacts/TestLogDecodingDownstream.json';
import * as TestOwnable from '../generated-artifacts/TestOwnable.json';
import * as TestReentrancyGuard from '../generated-artifacts/TestReentrancyGuard.json';
import * as TestRefundable from '../generated-artifacts/TestRefundable.json';
import * as TestSafeMath from '../generated-artifacts/TestSafeMath.json';
export const artifacts = {
Authorizable: Authorizable as ContractArtifact,
@@ -51,6 +53,7 @@ export const artifacts = {
LibSafeMathRichErrors: LibSafeMathRichErrors as ContractArtifact,
Ownable: Ownable as ContractArtifact,
ReentrancyGuard: ReentrancyGuard as ContractArtifact,
Refundable: Refundable as ContractArtifact,
SafeMath: SafeMath as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IOwnable: IOwnable as ContractArtifact,
@@ -63,5 +66,6 @@ export const artifacts = {
TestLogDecodingDownstream: TestLogDecodingDownstream as ContractArtifact,
TestOwnable: TestOwnable as ContractArtifact,
TestReentrancyGuard: TestReentrancyGuard as ContractArtifact,
TestRefundable: TestRefundable as ContractArtifact,
TestSafeMath: TestSafeMath as ContractArtifact,
};

View File

@@ -21,6 +21,7 @@ export * from '../generated-wrappers/lib_safe_math';
export * from '../generated-wrappers/lib_safe_math_rich_errors';
export * from '../generated-wrappers/ownable';
export * from '../generated-wrappers/reentrancy_guard';
export * from '../generated-wrappers/refundable';
export * from '../generated-wrappers/safe_math';
export * from '../generated-wrappers/test_lib_address';
export * from '../generated-wrappers/test_lib_address_array';
@@ -31,4 +32,5 @@ export * from '../generated-wrappers/test_log_decoding';
export * from '../generated-wrappers/test_log_decoding_downstream';
export * from '../generated-wrappers/test_ownable';
export * from '../generated-wrappers/test_reentrancy_guard';
export * from '../generated-wrappers/test_refundable';
export * from '../generated-wrappers/test_safe_math';

View File

@@ -0,0 +1,85 @@
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import * as _ from 'lodash';
import { artifacts, TestRefundableContract } from '../src';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('Refundable', () => {
let owner: string;
let notOwner: string;
let address: string;
let refundable: TestRefundableContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
[owner, address, notOwner] = _.slice(accounts, 0, 3);
refundable = await TestRefundableContract.deployFrom0xArtifactAsync(
artifacts.TestRefundable,
provider,
txDefaults,
{},
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('refund', async () => {
it('should refund all of the ether sent to the simpleRefundFunction', async () => {
await expect(
refundable.simpleRefundFunction.sendTransactionAsync({
from: owner,
value: Web3Wrapper.toBaseUnitAmount(1, 18),
}),
).to.be.fulfilled(''); // tslint:disable-line:await-promise
expect(await web3Wrapper.getBalanceInWeiAsync(refundable.address)).bignumber.to.be.eq(
constants.ZERO_AMOUNT,
);
});
it('should refund all of the ether sent to the simpleReentrantRefundFunction with a counter of 2', async () => {
await expect(
refundable.simpleReentrantRefundFunction.sendTransactionAsync({
from: owner,
value: Web3Wrapper.toBaseUnitAmount(1, 18),
}),
).to.be.fulfilled(''); // tslint:disable-line:await-promise
expect(await web3Wrapper.getBalanceInWeiAsync(refundable.address)).bignumber.to.be.eq(
constants.ZERO_AMOUNT,
);
});
it('should refund all of the ether sent to the complexReentrantRefundFunction with a counter of 2', async () => {
await expect(
refundable.complexReentrantRefundFunction.sendTransactionAsync({
from: owner,
value: Web3Wrapper.toBaseUnitAmount(1, 18),
}),
).to.be.fulfilled(''); // tslint:disable-line:await-promise
expect(await web3Wrapper.getBalanceInWeiAsync(refundable.address)).bignumber.to.be.eq(
constants.ZERO_AMOUNT,
);
});
// FIXME - Receiver tests
});
});

View File

@@ -21,6 +21,7 @@
"generated-artifacts/LibSafeMathRichErrors.json",
"generated-artifacts/Ownable.json",
"generated-artifacts/ReentrancyGuard.json",
"generated-artifacts/Refundable.json",
"generated-artifacts/SafeMath.json",
"generated-artifacts/TestLibAddress.json",
"generated-artifacts/TestLibAddressArray.json",
@@ -31,6 +32,7 @@
"generated-artifacts/TestLogDecodingDownstream.json",
"generated-artifacts/TestOwnable.json",
"generated-artifacts/TestReentrancyGuard.json",
"generated-artifacts/TestRefundable.json",
"generated-artifacts/TestSafeMath.json"
],
"exclude": ["./deploy/solc/solc_bin"]