@0x:contracts-utils Added a Refundable contract
This commit is contained in:
@@ -24,12 +24,20 @@ contract Refundable {
|
||||
// This bool is used by the refund modifier to allow for lazily evaluated refunds.
|
||||
bool internal shouldNotRefund;
|
||||
|
||||
modifier refund {
|
||||
modifier refundFinalBalance {
|
||||
_;
|
||||
if (!shouldNotRefund) {
|
||||
msg.sender.transfer(address(this).balance);
|
||||
}
|
||||
}
|
||||
|
||||
modifier disableRefundUntilEnd {
|
||||
if (shouldNotRefund) {
|
||||
_;
|
||||
} else {
|
||||
shouldNotRefund = true;
|
||||
_;
|
||||
shouldNotRefund = false;
|
||||
msg.sender.transfer(address(this).balance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,43 +24,49 @@ import "../src/Refundable.sol";
|
||||
contract TestRefundable is
|
||||
Refundable
|
||||
{
|
||||
uint256 public counter = 2;
|
||||
|
||||
function setCounter(uint256 newCounter)
|
||||
function setShouldNotRefund(bool shouldNotRefundNew)
|
||||
external
|
||||
{
|
||||
counter = newCounter;
|
||||
shouldNotRefund = shouldNotRefundNew;
|
||||
}
|
||||
|
||||
function complexReentrantRefundFunction()
|
||||
function getShouldNotRefund()
|
||||
external
|
||||
payable
|
||||
refund()
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
if (counter == 0) {
|
||||
// This call tests lazy evaluation across different functions with the refund modifier
|
||||
this.simpleRefundFunction();
|
||||
} else {
|
||||
counter--;
|
||||
this.complexReentrantRefundFunction();
|
||||
}
|
||||
return shouldNotRefund;
|
||||
}
|
||||
|
||||
function simpleReentrantRefundFunction()
|
||||
external
|
||||
function refundFinalBalanceFunction()
|
||||
public
|
||||
payable
|
||||
refund()
|
||||
{
|
||||
if (counter != 0) {
|
||||
counter--;
|
||||
this.simpleReentrantRefundFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function simpleRefundFunction()
|
||||
external
|
||||
payable
|
||||
refund()
|
||||
refundFinalBalance
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
function disableRefundUntilEndFunction()
|
||||
public
|
||||
payable
|
||||
disableRefundUntilEnd
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
function nestedDisableRefundUntilEndFunction()
|
||||
public
|
||||
payable
|
||||
disableRefundUntilEnd
|
||||
returns (uint256)
|
||||
{
|
||||
disableRefundUntilEndFunction();
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function mixedRefundModifierFunction()
|
||||
public
|
||||
payable
|
||||
disableRefundUntilEnd
|
||||
returns (uint256)
|
||||
{
|
||||
refundFinalBalanceFunction();
|
||||
return address(this).balance;
|
||||
}
|
||||
}
|
||||
|
||||
168
contracts/utils/contracts/test/TestRefundableReceiver.sol
Normal file
168
contracts/utils/contracts/test/TestRefundableReceiver.sol
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
|
||||
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 "./TestRefundable.sol";
|
||||
|
||||
|
||||
contract TestRefundableReceiver {
|
||||
|
||||
/// @dev A payable fallback function is necessary to receive refunds from the `TestRefundable` contract.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
/// @dev This function tests the behavior to a simple call to `refundFinalBalanceFunction`. This
|
||||
/// test will verify that the correct refund was provided after the call (depending on whether
|
||||
/// a refund should be provided), and it will ensure that the `shouldNotRefund` state variable
|
||||
/// remains unaltered after the function call.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
/// @param shouldNotRefund The value that shouldNotRefund should be set to before the call to TestRefundable.
|
||||
function testRefundFinalBalance(
|
||||
TestRefundable testRefundable,
|
||||
bool shouldNotRefund
|
||||
)
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Set `shouldNotRefund` to the specified bool.
|
||||
testRefundable.setShouldNotRefund(shouldNotRefund);
|
||||
|
||||
// Call `refundFinalBalanceFunction` and forward all value from the contract.
|
||||
testRefundable.refundFinalBalanceFunction.value(msg.value)();
|
||||
|
||||
// Assert that the expected refunds happened and that the `shouldNotRefund` value was
|
||||
// set back to an unaltered state after the call.
|
||||
requireCorrectFinalBalancesAndState(testRefundable, shouldNotRefund);
|
||||
}
|
||||
|
||||
/// @dev This function tests the behavior to a simple call to `disableRefundUntilEndFunction`. This
|
||||
/// test will verify that the correct refund was provided after the call (depending on whether
|
||||
/// a refund should be provided), and it will ensure that the `shouldNotRefund` state variable
|
||||
/// remains unaltered after the function call.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
/// @param shouldNotRefund The value that shouldNotRefund should be set to before the call to TestRefundable.
|
||||
function testDisableRefundUntilEnd(
|
||||
TestRefundable testRefundable,
|
||||
bool shouldNotRefund
|
||||
)
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Set `shouldNotRefund` to the specified bool.
|
||||
testRefundable.setShouldNotRefund(shouldNotRefund);
|
||||
|
||||
// Call `disableRefundUntilEndFunction` and forward all value from the contract.
|
||||
testRefundable.disableRefundUntilEndFunction.value(msg.value)();
|
||||
|
||||
// Assert that the expected refunds happened and that the `shouldNotRefund` value was
|
||||
// set back to an unaltered state after the call.
|
||||
requireCorrectFinalBalancesAndState(testRefundable, shouldNotRefund);
|
||||
}
|
||||
|
||||
/// @dev This function tests the behavior of a call to a function that has the `disableRefundUntilEndFunction`.
|
||||
/// The function that is called also uses the `disableRefundUntilEndFunction`, so this function's role is
|
||||
/// to verify that both the inner and outer modifiers worked correctly.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
/// @param shouldNotRefund The value that shouldNotRefund should be set to before the call to TestRefundable.
|
||||
function testNestedDisableRefundUntilEnd(
|
||||
TestRefundable testRefundable,
|
||||
bool shouldNotRefund
|
||||
)
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Set `shouldNotRefund` to the specified bool.
|
||||
testRefundable.setShouldNotRefund(shouldNotRefund);
|
||||
|
||||
// Call `nestedDisableRefundUntilEndFunction` and forward all value from the contract.
|
||||
uint256 balanceWithinCall = testRefundable.nestedDisableRefundUntilEndFunction.value(msg.value)();
|
||||
|
||||
// Ensure that the balance within the call was equal to `msg.value` since the inner refund should
|
||||
// not have been triggered regardless of the value of `shouldNotRefund`.
|
||||
require(balanceWithinCall == msg.value, "Incorrect inner balance");
|
||||
|
||||
// Assert that the expected refunds happened and that the `shouldNotRefund` value was
|
||||
// set back to an unaltered state after the call.
|
||||
requireCorrectFinalBalancesAndState(testRefundable, shouldNotRefund);
|
||||
}
|
||||
|
||||
/// @dev This function tests the behavior of a call to a function that has the `disableRefundUntilEndFunction`.
|
||||
/// The function that is called uses the `refundFinalBalanceFunction`, so this function's role is
|
||||
/// to verify that both the inner and outer modifiers worked correctly.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
/// @param shouldNotRefund The value that shouldNotRefund should be set to before the call to TestRefundable.
|
||||
function testMixedRefunds(
|
||||
TestRefundable testRefundable,
|
||||
bool shouldNotRefund
|
||||
)
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Set `shouldNotRefund` to the specified bool.
|
||||
testRefundable.setShouldNotRefund(shouldNotRefund);
|
||||
|
||||
// Call `mixedRefundModifierFunction` and forward all value from the contract.
|
||||
uint256 balanceWithinCall = testRefundable.mixedRefundModifierFunction.value(msg.value)();
|
||||
|
||||
// Ensure that the balance within the call was equal to `msg.value` since the inner refund should
|
||||
// not have been triggered regardless of the value of `shouldNotRefund`.
|
||||
require(balanceWithinCall == msg.value, "Incorrect inner balance");
|
||||
|
||||
// Assert that the expected refunds happened and that the `shouldNotRefund` value was
|
||||
// set back to an unaltered state after the call.
|
||||
requireCorrectFinalBalancesAndState(testRefundable, shouldNotRefund);
|
||||
}
|
||||
|
||||
/// @dev This helper function verifies the final balances of this receiver contract and a specified
|
||||
/// refundable contract and verifies that the `shouldNotRefund` value remains unaltered.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
/// @param shouldNotRefund The value that shouldNotRefund was set to before the call to TestRefundable.
|
||||
function requireCorrectFinalBalancesAndState(
|
||||
TestRefundable testRefundable,
|
||||
bool shouldNotRefund
|
||||
)
|
||||
internal
|
||||
{
|
||||
// If `shouldNotRefund` was true, then this contract should have a balance of zero,
|
||||
// and `testRefundable` should have a balance of `msg.value`. Otherwise, the opposite
|
||||
// should be true.
|
||||
if (shouldNotRefund) {
|
||||
// Ensure that this contract's balance is zero.
|
||||
require(address(this).balance == 0, "Incorrect balance for TestRefundableReceiver");
|
||||
|
||||
// Ensure that the other contract's balance is equal to `msg.value`.
|
||||
require(address(testRefundable).balance == msg.value, "Incorrect balance for TestRefundable");
|
||||
} else {
|
||||
// Ensure that this contract's balance is `msg.value`.
|
||||
require(address(this).balance == msg.value, "Incorrect balance for TestRefundableReceiver");
|
||||
|
||||
// Ensure that the other contract's balance is equal to zero.
|
||||
require(address(testRefundable).balance == 0, "Incorrect balance for TestRefundable");
|
||||
}
|
||||
|
||||
// Ensure that `shouldNotRefund` in TestRefundable is set to the parameter `shouldNotRefund`
|
||||
// after the call (i.e. the value didn't change during the function call).
|
||||
require(testRefundable.getShouldNotRefund() == shouldNotRefund, "Incorrect shouldNotRefund value");
|
||||
|
||||
// Drain the contract of funds so that subsequent tests don't have to account for leftover ether.
|
||||
msg.sender.transfer(address(this).balance);
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,8 @@
|
||||
"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|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."
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"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|TestRefundableReceiver|TestSafeMath).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -35,6 +35,7 @@ import * as TestLogDecodingDownstream from '../generated-artifacts/TestLogDecodi
|
||||
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 TestRefundableReceiver from '../generated-artifacts/TestRefundableReceiver.json';
|
||||
import * as TestSafeMath from '../generated-artifacts/TestSafeMath.json';
|
||||
export const artifacts = {
|
||||
Authorizable: Authorizable as ContractArtifact,
|
||||
@@ -67,5 +68,6 @@ export const artifacts = {
|
||||
TestOwnable: TestOwnable as ContractArtifact,
|
||||
TestReentrancyGuard: TestReentrancyGuard as ContractArtifact,
|
||||
TestRefundable: TestRefundable as ContractArtifact,
|
||||
TestRefundableReceiver: TestRefundableReceiver as ContractArtifact,
|
||||
TestSafeMath: TestSafeMath as ContractArtifact,
|
||||
};
|
||||
|
||||
@@ -33,4 +33,5 @@ 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_refundable_receiver';
|
||||
export * from '../generated-wrappers/test_safe_math';
|
||||
|
||||
@@ -1,85 +1,118 @@
|
||||
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 { blockchainTests } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestRefundableContract } from '../src';
|
||||
import { artifacts, TestRefundableContract, TestRefundableReceiverContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('Refundable', () => {
|
||||
let owner: string;
|
||||
let notOwner: string;
|
||||
let address: string;
|
||||
blockchainTests('Refundable', env => {
|
||||
let refundable: TestRefundableContract;
|
||||
let receiver: TestRefundableReceiverContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[owner, address, notOwner] = _.slice(accounts, 0, 3);
|
||||
// Create the refundable contract.
|
||||
refundable = await TestRefundableContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestRefundable,
|
||||
provider,
|
||||
txDefaults,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
|
||||
// Create the receiver contract.
|
||||
receiver = await TestRefundableReceiverContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestRefundableReceiver,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
// The contents of these typescript tests is not adequate to understand the assertions that are made during
|
||||
// these calls. For a more accurate picture, checkout out "./contracts/test/TestRefundableReceiver.sol".
|
||||
blockchainTests.resets('refundFinalBalance', async () => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
// This test may not be necessary, but it is included here as a sanity check.
|
||||
it('should fully refund the sender when `shouldNotRefund` is false for two calls in a row', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
|
||||
// Send 1000 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(1000),
|
||||
});
|
||||
});
|
||||
|
||||
it('should not refund the sender if `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, true, {
|
||||
value: new BigNumber(1000),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
);
|
||||
// The contents of these typescript tests is not adequate to understand the assertions that are made during
|
||||
// these calls. For a more accurate picture, checkout out "./contracts/test/TestRefundableReceiver.sol".
|
||||
blockchainTests.resets('disableRefundUntilEnd', async () => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
);
|
||||
// This test may not be necessary, but it is included here as a sanity check.
|
||||
it('should fully refund the sender when `shouldNotRefund` is false for two calls in a row', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
|
||||
// Send 1000 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(1000),
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
);
|
||||
it('should not refund the sender if `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
// FIXME - Receiver tests
|
||||
it('should disable the `disableRefundUntilEnd` modifier and refund when `shouldNotRefund` is false', async () => {
|
||||
/// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testNestedDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and send no refund when `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testNestedDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, true, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and refund when `shouldNotRefund` is false', async () => {
|
||||
/// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testMixedRefunds.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and send no refund when `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testMixedRefunds.awaitTransactionSuccessAsync(refundable.address, true, {
|
||||
value: new BigNumber(100),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"generated-artifacts/TestOwnable.json",
|
||||
"generated-artifacts/TestReentrancyGuard.json",
|
||||
"generated-artifacts/TestRefundable.json",
|
||||
"generated-artifacts/TestRefundableReceiver.json",
|
||||
"generated-artifacts/TestSafeMath.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
|
||||
Reference in New Issue
Block a user