Add contracts to packages, fix most linting errors
This commit is contained in:
602
packages/contracts/contracts/Exchange.sol
Normal file
602
packages/contracts/contracts/Exchange.sol
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./TokenTransferProxy.sol";
|
||||
import "./base/Token.sol";
|
||||
import "./base/SafeMath.sol";
|
||||
|
||||
/// @title Exchange - Facilitates exchange of ERC20 tokens.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract Exchange is SafeMath {
|
||||
|
||||
// Error Codes
|
||||
enum Errors {
|
||||
ORDER_EXPIRED, // Order has already expired
|
||||
ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled
|
||||
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
|
||||
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
|
||||
}
|
||||
|
||||
string constant public VERSION = "1.0.0";
|
||||
uint16 constant public EXTERNAL_QUERY_GAS_LIMIT = 4999; // Changes to state require at least 5000 gas
|
||||
|
||||
address public ZRX_TOKEN_CONTRACT;
|
||||
address public TOKEN_TRANSFER_PROXY_CONTRACT;
|
||||
|
||||
// Mappings of orderHash => amounts of takerTokenAmount filled or cancelled.
|
||||
mapping (bytes32 => uint) public filled;
|
||||
mapping (bytes32 => uint) public cancelled;
|
||||
|
||||
event LogFill(
|
||||
address indexed maker,
|
||||
address taker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint filledMakerTokenAmount,
|
||||
uint filledTakerTokenAmount,
|
||||
uint paidMakerFee,
|
||||
uint paidTakerFee,
|
||||
bytes32 indexed tokens, // keccak256(makerToken, takerToken), allows subscribing to a token pair
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogCancel(
|
||||
address indexed maker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint cancelledMakerTokenAmount,
|
||||
uint cancelledTakerTokenAmount,
|
||||
bytes32 indexed tokens,
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogError(uint8 indexed errorId, bytes32 indexed orderHash);
|
||||
|
||||
struct Order {
|
||||
address maker;
|
||||
address taker;
|
||||
address makerToken;
|
||||
address takerToken;
|
||||
address feeRecipient;
|
||||
uint makerTokenAmount;
|
||||
uint takerTokenAmount;
|
||||
uint makerFee;
|
||||
uint takerFee;
|
||||
uint expirationTimestampInSec;
|
||||
bytes32 orderHash;
|
||||
}
|
||||
|
||||
function Exchange(address _zrxToken, address _tokenTransferProxy) {
|
||||
ZRX_TOKEN_CONTRACT = _zrxToken;
|
||||
TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Core exchange functions
|
||||
*/
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfer will fail before attempting.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Total amount of takerToken filled in trade.
|
||||
function fillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
returns (uint filledTakerTokenAmount)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.taker == address(0) || order.taker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && fillTakerTokenAmount > 0);
|
||||
require(isValidSignature(
|
||||
order.maker,
|
||||
order.orderHash,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
));
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
filledTakerTokenAmount = min256(fillTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (filledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isRoundingError(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount)) {
|
||||
LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!shouldThrowOnInsufficientBalanceOrAllowance && !isTransferable(order, filledTakerTokenAmount)) {
|
||||
LogError(uint8(Errors.INSUFFICIENT_BALANCE_OR_ALLOWANCE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint filledMakerTokenAmount = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
uint paidMakerFee;
|
||||
uint paidTakerFee;
|
||||
filled[order.orderHash] = safeAdd(filled[order.orderHash], filledTakerTokenAmount);
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.makerToken,
|
||||
order.maker,
|
||||
msg.sender,
|
||||
filledMakerTokenAmount
|
||||
));
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.takerToken,
|
||||
msg.sender,
|
||||
order.maker,
|
||||
filledTakerTokenAmount
|
||||
));
|
||||
if (order.feeRecipient != address(0)) {
|
||||
if (order.makerFee > 0) {
|
||||
paidMakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
paidMakerFee
|
||||
));
|
||||
}
|
||||
if (order.takerFee > 0) {
|
||||
paidTakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
paidTakerFee
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
LogFill(
|
||||
order.maker,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
filledMakerTokenAmount,
|
||||
filledTakerTokenAmount,
|
||||
paidMakerFee,
|
||||
paidTakerFee,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Cancels the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param cancelTakerTokenAmount Desired amount of takerToken to cancel in order.
|
||||
/// @return Amount of takerToken cancelled.
|
||||
function cancelOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint cancelTakerTokenAmount)
|
||||
public
|
||||
returns (uint)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.maker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && cancelTakerTokenAmount > 0);
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
uint cancelledTakerTokenAmount = min256(cancelTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (cancelledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cancelled[order.orderHash] = safeAdd(cancelled[order.orderHash], cancelledTakerTokenAmount);
|
||||
|
||||
LogCancel(
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
getPartialAmount(cancelledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount),
|
||||
cancelledTakerTokenAmount,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return cancelledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper functions
|
||||
*/
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature, throws if specified amount not filled entirely.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
function fillOrKillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
{
|
||||
require(fillOrder(
|
||||
orderAddresses,
|
||||
orderValues,
|
||||
fillTakerTokenAmount,
|
||||
false,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
) == fillTakerTokenAmount);
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fillOrKill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrKillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrKillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total fillTakerTokenAmount filled.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmount Desired total amount of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
/// @return Total amount of fillTakerTokenAmount filled in orders.
|
||||
function fillOrdersUpTo(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
returns (uint)
|
||||
{
|
||||
uint filledTakerTokenAmount = 0;
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
require(orderAddresses[i][3] == orderAddresses[0][3]); // takerToken must be the same for each order
|
||||
filledTakerTokenAmount = safeAdd(filledTakerTokenAmount, fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
safeSub(fillTakerTokenAmount, filledTakerTokenAmount),
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
));
|
||||
if (filledTakerTokenAmount == fillTakerTokenAmount) break;
|
||||
}
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param cancelTakerTokenAmounts Array of desired amounts of takerToken to cancel in orders.
|
||||
function batchCancelOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] cancelTakerTokenAmounts)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
cancelOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
cancelTakerTokenAmounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constant public functions
|
||||
*/
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of order with specified parameters.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @return Keccak-256 hash of order.
|
||||
function getOrderHash(address[5] orderAddresses, uint[6] orderValues)
|
||||
public
|
||||
constant
|
||||
returns (bytes32)
|
||||
{
|
||||
return keccak256(
|
||||
address(this),
|
||||
orderAddresses[0], // maker
|
||||
orderAddresses[1], // taker
|
||||
orderAddresses[2], // makerToken
|
||||
orderAddresses[3], // takerToken
|
||||
orderAddresses[4], // feeRecipient
|
||||
orderValues[0], // makerTokenAmount
|
||||
orderValues[1], // takerTokenAmount
|
||||
orderValues[2], // makerFee
|
||||
orderValues[3], // takerFee
|
||||
orderValues[4], // expirationTimestampInSec
|
||||
orderValues[5] // salt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Verifies that an order signature is valid.
|
||||
/// @param signer address of signer.
|
||||
/// @param hash Signed Keccak-256 hash.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
address signer,
|
||||
bytes32 hash,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
return signer == ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n32", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
uint remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) return false; // No rounding error.
|
||||
|
||||
uint errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
);
|
||||
return errPercentageTimes1000000 > 1000;
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeDiv(safeMul(numerator, target), denominator);
|
||||
}
|
||||
|
||||
/// @dev Calculates the sum of values already filled and cancelled for a given order.
|
||||
/// @param orderHash The Keccak-256 hash of the given order.
|
||||
/// @return Sum of values already filled and cancelled.
|
||||
function getUnavailableTakerTokenAmount(bytes32 orderHash)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeAdd(filled[orderHash], cancelled[orderHash]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
|
||||
/// @dev Transfers a token using TokenTransferProxy transferFrom function.
|
||||
/// @param token Address of token to transferFrom.
|
||||
/// @param from Address transfering token.
|
||||
/// @param to Address receiving token.
|
||||
/// @param value Amount of token to transfer.
|
||||
/// @return Success of token transfer.
|
||||
function transferViaTokenTransferProxy(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint value)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return TokenTransferProxy(TOKEN_TRANSFER_PROXY_CONTRACT).transferFrom(token, from, to, value);
|
||||
}
|
||||
|
||||
/// @dev Checks if any order transfers will fail.
|
||||
/// @param order Order struct of params that will be checked.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @return Predicted result of transfers.
|
||||
function isTransferable(Order order, uint fillTakerTokenAmount)
|
||||
internal
|
||||
constant // The called token contracts may attempt to change state, but will not be able to due to gas limits on getBalance and getAllowance.
|
||||
returns (bool)
|
||||
{
|
||||
address taker = msg.sender;
|
||||
uint fillMakerTokenAmount = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
|
||||
if (order.feeRecipient != address(0)) {
|
||||
bool isMakerTokenZRX = order.makerToken == ZRX_TOKEN_CONTRACT;
|
||||
bool isTakerTokenZRX = order.takerToken == ZRX_TOKEN_CONTRACT;
|
||||
uint paidMakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
uint paidTakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
uint requiredMakerZRX = isMakerTokenZRX ? safeAdd(fillMakerTokenAmount, paidMakerFee) : paidMakerFee;
|
||||
uint requiredTakerZRX = isTakerTokenZRX ? safeAdd(fillTakerTokenAmount, paidTakerFee) : paidTakerFee;
|
||||
|
||||
if ( getBalance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getBalance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
) return false;
|
||||
|
||||
if (!isMakerTokenZRX && ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount // Don't double check makerToken if ZRX
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount)
|
||||
) return false;
|
||||
if (!isTakerTokenZRX && ( getBalance(order.takerToken, taker) < fillTakerTokenAmount // Don't double check takerToken if ZRX
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount)
|
||||
) return false;
|
||||
} else if ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getBalance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Get token balance of an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Token balance of owner.
|
||||
function getBalance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).balanceOf.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner); // Limit gas to prevent reentrancy
|
||||
}
|
||||
|
||||
/// @dev Get allowance of token given to TokenTransferProxy by an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Allowance of token given to TokenTransferProxy by owner.
|
||||
function getAllowance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy
|
||||
}
|
||||
}
|
132
packages/contracts/contracts/MultiSigWalletWithTimeLock.sol
Normal file
132
packages/contracts/contracts/MultiSigWalletWithTimeLock.sol
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./base/MultiSigWallet.sol";
|
||||
|
||||
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>
|
||||
contract MultiSigWalletWithTimeLock is MultiSigWallet {
|
||||
|
||||
event ConfirmationTimeSet(uint indexed transactionId, uint confirmationTime);
|
||||
event TimeLockChange(uint secondsTimeLocked);
|
||||
|
||||
uint public secondsTimeLocked;
|
||||
|
||||
mapping (uint => uint) public confirmationTimes;
|
||||
|
||||
modifier notFullyConfirmed(uint transactionId) {
|
||||
require(!isConfirmed(transactionId));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier fullyConfirmed(uint transactionId) {
|
||||
require(isConfirmed(transactionId));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier pastTimeLock(uint transactionId) {
|
||||
require(block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked);
|
||||
_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/// @dev Contract constructor sets initial owners, required number of confirmations, and time lock.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function MultiSigWalletWithTimeLock(address[] _owners, uint _required, uint _secondsTimeLocked)
|
||||
public
|
||||
MultiSigWallet(_owners, _required)
|
||||
{
|
||||
secondsTimeLocked = _secondsTimeLocked;
|
||||
}
|
||||
|
||||
/// @dev Changes the duration of the time lock for transactions.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function changeTimeLock(uint _secondsTimeLocked)
|
||||
public
|
||||
onlyWallet
|
||||
{
|
||||
secondsTimeLocked = _secondsTimeLocked;
|
||||
TimeLockChange(_secondsTimeLocked);
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to confirm a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function confirmTransaction(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
transactionExists(transactionId)
|
||||
notConfirmed(transactionId, msg.sender)
|
||||
notFullyConfirmed(transactionId)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = true;
|
||||
Confirmation(msg.sender, transactionId);
|
||||
if (isConfirmed(transactionId)) {
|
||||
setConfirmationTime(transactionId, block.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to revoke a confirmation for a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function revokeConfirmation(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
confirmed(transactionId, msg.sender)
|
||||
notExecuted(transactionId)
|
||||
notFullyConfirmed(transactionId)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = false;
|
||||
Revocation(msg.sender, transactionId);
|
||||
}
|
||||
|
||||
/// @dev Allows anyone to execute a confirmed transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeTransaction(uint transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
fullyConfirmed(transactionId)
|
||||
pastTimeLock(transactionId)
|
||||
{
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
|
||||
/// @dev Sets the time of when a submission first passed.
|
||||
function setConfirmationTime(uint transactionId, uint confirmationTime)
|
||||
internal
|
||||
{
|
||||
confirmationTimes[transactionId] = confirmationTime;
|
||||
ConfirmationTimeSet(transactionId, confirmationTime);
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./MultiSigWalletWithTimeLock.sol";
|
||||
|
||||
contract MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress is MultiSigWalletWithTimeLock {
|
||||
|
||||
address public TOKEN_TRANSFER_PROXY_CONTRACT;
|
||||
|
||||
modifier validRemoveAuthorizedAddressTx(uint transactionId) {
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
require(tx.destination == TOKEN_TRANSFER_PROXY_CONTRACT);
|
||||
require(isFunctionRemoveAuthorizedAddress(tx.data));
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Contract constructor sets initial owners, required number of confirmations, time lock, and tokenTransferProxy address.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
/// @param _tokenTransferProxy Address of TokenTransferProxy contract.
|
||||
function MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress(
|
||||
address[] _owners,
|
||||
uint _required,
|
||||
uint _secondsTimeLocked,
|
||||
address _tokenTransferProxy)
|
||||
public
|
||||
MultiSigWalletWithTimeLock(_owners, _required, _secondsTimeLocked)
|
||||
{
|
||||
TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy;
|
||||
}
|
||||
|
||||
/// @dev Allows execution of removeAuthorizedAddress without time lock.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeRemoveAuthorizedAddress(uint transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
fullyConfirmed(transactionId)
|
||||
validRemoveAuthorizedAddressTx(transactionId)
|
||||
{
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Compares first 4 bytes of byte array to removeAuthorizedAddress function signature.
|
||||
/// @param data Transaction data.
|
||||
/// @return Successful if data is a call to removeAuthorizedAddress.
|
||||
function isFunctionRemoveAuthorizedAddress(bytes data)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
bytes4 removeAuthorizedAddressSignature = bytes4(sha3("removeAuthorizedAddress(address)"));
|
||||
for (uint i = 0; i < 4; i++) {
|
||||
require(data[i] == removeAuthorizedAddressSignature[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
308
packages/contracts/contracts/TokenRegistry.sol
Normal file
308
packages/contracts/contracts/TokenRegistry.sol
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./base/Ownable.sol";
|
||||
|
||||
/// @title Token Registry - Stores metadata associated with ERC20 tokens. See ERC22 https://github.com/ethereum/EIPs/issues/22
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract TokenRegistry is Ownable {
|
||||
|
||||
event LogAddToken(
|
||||
address indexed token,
|
||||
string name,
|
||||
string symbol,
|
||||
uint8 decimals,
|
||||
bytes ipfsHash,
|
||||
bytes swarmHash
|
||||
);
|
||||
|
||||
event LogRemoveToken(
|
||||
address indexed token,
|
||||
string name,
|
||||
string symbol,
|
||||
uint8 decimals,
|
||||
bytes ipfsHash,
|
||||
bytes swarmHash
|
||||
);
|
||||
|
||||
event LogTokenNameChange(address indexed token, string oldName, string newName);
|
||||
event LogTokenSymbolChange(address indexed token, string oldSymbol, string newSymbol);
|
||||
event LogTokenIpfsHashChange(address indexed token, bytes oldIpfsHash, bytes newIpfsHash);
|
||||
event LogTokenSwarmHashChange(address indexed token, bytes oldSwarmHash, bytes newSwarmHash);
|
||||
|
||||
mapping (address => TokenMetadata) public tokens;
|
||||
mapping (string => address) tokenBySymbol;
|
||||
mapping (string => address) tokenByName;
|
||||
|
||||
address[] public tokenAddresses;
|
||||
|
||||
struct TokenMetadata {
|
||||
address token;
|
||||
string name;
|
||||
string symbol;
|
||||
uint8 decimals;
|
||||
bytes ipfsHash;
|
||||
bytes swarmHash;
|
||||
}
|
||||
|
||||
modifier tokenExists(address _token) {
|
||||
require(tokens[_token].token != address(0));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier tokenDoesNotExist(address _token) {
|
||||
require(tokens[_token].token == address(0));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier nameDoesNotExist(string _name) {
|
||||
require(tokenByName[_name] == address(0));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier symbolDoesNotExist(string _symbol) {
|
||||
require(tokenBySymbol[_symbol] == address(0));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier addressNotNull(address _address) {
|
||||
require(_address != address(0));
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
/// @dev Allows owner to add a new token to the registry.
|
||||
/// @param _token Address of new token.
|
||||
/// @param _name Name of new token.
|
||||
/// @param _symbol Symbol for new token.
|
||||
/// @param _decimals Number of decimals, divisibility of new token.
|
||||
/// @param _ipfsHash IPFS hash of token icon.
|
||||
/// @param _swarmHash Swarm hash of token icon.
|
||||
function addToken(
|
||||
address _token,
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint8 _decimals,
|
||||
bytes _ipfsHash,
|
||||
bytes _swarmHash)
|
||||
public
|
||||
onlyOwner
|
||||
tokenDoesNotExist(_token)
|
||||
addressNotNull(_token)
|
||||
symbolDoesNotExist(_symbol)
|
||||
nameDoesNotExist(_name)
|
||||
{
|
||||
tokens[_token] = TokenMetadata({
|
||||
token: _token,
|
||||
name: _name,
|
||||
symbol: _symbol,
|
||||
decimals: _decimals,
|
||||
ipfsHash: _ipfsHash,
|
||||
swarmHash: _swarmHash
|
||||
});
|
||||
tokenAddresses.push(_token);
|
||||
tokenBySymbol[_symbol] = _token;
|
||||
tokenByName[_name] = _token;
|
||||
LogAddToken(
|
||||
_token,
|
||||
_name,
|
||||
_symbol,
|
||||
_decimals,
|
||||
_ipfsHash,
|
||||
_swarmHash
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Allows owner to remove an existing token from the registry.
|
||||
/// @param _token Address of existing token.
|
||||
function removeToken(address _token, uint _index)
|
||||
public
|
||||
onlyOwner
|
||||
tokenExists(_token)
|
||||
{
|
||||
require(tokenAddresses[_index] == _token);
|
||||
|
||||
tokenAddresses[_index] = tokenAddresses[tokenAddresses.length - 1];
|
||||
tokenAddresses.length -= 1;
|
||||
|
||||
TokenMetadata storage token = tokens[_token];
|
||||
LogRemoveToken(
|
||||
token.token,
|
||||
token.name,
|
||||
token.symbol,
|
||||
token.decimals,
|
||||
token.ipfsHash,
|
||||
token.swarmHash
|
||||
);
|
||||
delete tokenBySymbol[token.symbol];
|
||||
delete tokenByName[token.name];
|
||||
delete tokens[_token];
|
||||
}
|
||||
|
||||
/// @dev Allows owner to modify an existing token's name.
|
||||
/// @param _token Address of existing token.
|
||||
/// @param _name New name.
|
||||
function setTokenName(address _token, string _name)
|
||||
public
|
||||
onlyOwner
|
||||
tokenExists(_token)
|
||||
nameDoesNotExist(_name)
|
||||
{
|
||||
TokenMetadata storage token = tokens[_token];
|
||||
LogTokenNameChange(_token, token.name, _name);
|
||||
delete tokenByName[token.name];
|
||||
tokenByName[_name] = _token;
|
||||
token.name = _name;
|
||||
}
|
||||
|
||||
/// @dev Allows owner to modify an existing token's symbol.
|
||||
/// @param _token Address of existing token.
|
||||
/// @param _symbol New symbol.
|
||||
function setTokenSymbol(address _token, string _symbol)
|
||||
public
|
||||
onlyOwner
|
||||
tokenExists(_token)
|
||||
symbolDoesNotExist(_symbol)
|
||||
{
|
||||
TokenMetadata storage token = tokens[_token];
|
||||
LogTokenSymbolChange(_token, token.symbol, _symbol);
|
||||
delete tokenBySymbol[token.symbol];
|
||||
tokenBySymbol[_symbol] = _token;
|
||||
token.symbol = _symbol;
|
||||
}
|
||||
|
||||
/// @dev Allows owner to modify an existing token's IPFS hash.
|
||||
/// @param _token Address of existing token.
|
||||
/// @param _ipfsHash New IPFS hash.
|
||||
function setTokenIpfsHash(address _token, bytes _ipfsHash)
|
||||
public
|
||||
onlyOwner
|
||||
tokenExists(_token)
|
||||
{
|
||||
TokenMetadata storage token = tokens[_token];
|
||||
LogTokenIpfsHashChange(_token, token.ipfsHash, _ipfsHash);
|
||||
token.ipfsHash = _ipfsHash;
|
||||
}
|
||||
|
||||
/// @dev Allows owner to modify an existing token's Swarm hash.
|
||||
/// @param _token Address of existing token.
|
||||
/// @param _swarmHash New Swarm hash.
|
||||
function setTokenSwarmHash(address _token, bytes _swarmHash)
|
||||
public
|
||||
onlyOwner
|
||||
tokenExists(_token)
|
||||
{
|
||||
TokenMetadata storage token = tokens[_token];
|
||||
LogTokenSwarmHashChange(_token, token.swarmHash, _swarmHash);
|
||||
token.swarmHash = _swarmHash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Web3 call functions
|
||||
*/
|
||||
|
||||
/// @dev Provides a registered token's address when given the token symbol.
|
||||
/// @param _symbol Symbol of registered token.
|
||||
/// @return Token's address.
|
||||
function getTokenAddressBySymbol(string _symbol) constant returns (address) {
|
||||
return tokenBySymbol[_symbol];
|
||||
}
|
||||
|
||||
/// @dev Provides a registered token's address when given the token name.
|
||||
/// @param _name Name of registered token.
|
||||
/// @return Token's address.
|
||||
function getTokenAddressByName(string _name) constant returns (address) {
|
||||
return tokenByName[_name];
|
||||
}
|
||||
|
||||
/// @dev Provides a registered token's metadata, looked up by address.
|
||||
/// @param _token Address of registered token.
|
||||
/// @return Token metadata.
|
||||
function getTokenMetaData(address _token)
|
||||
public
|
||||
constant
|
||||
returns (
|
||||
address, //tokenAddress
|
||||
string, //name
|
||||
string, //symbol
|
||||
uint8, //decimals
|
||||
bytes, //ipfsHash
|
||||
bytes //swarmHash
|
||||
)
|
||||
{
|
||||
TokenMetadata memory token = tokens[_token];
|
||||
return (
|
||||
token.token,
|
||||
token.name,
|
||||
token.symbol,
|
||||
token.decimals,
|
||||
token.ipfsHash,
|
||||
token.swarmHash
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Provides a registered token's metadata, looked up by name.
|
||||
/// @param _name Name of registered token.
|
||||
/// @return Token metadata.
|
||||
function getTokenByName(string _name)
|
||||
public
|
||||
constant
|
||||
returns (
|
||||
address, //tokenAddress
|
||||
string, //name
|
||||
string, //symbol
|
||||
uint8, //decimals
|
||||
bytes, //ipfsHash
|
||||
bytes //swarmHash
|
||||
)
|
||||
{
|
||||
address _token = tokenByName[_name];
|
||||
return getTokenMetaData(_token);
|
||||
}
|
||||
|
||||
/// @dev Provides a registered token's metadata, looked up by symbol.
|
||||
/// @param _symbol Symbol of registered token.
|
||||
/// @return Token metadata.
|
||||
function getTokenBySymbol(string _symbol)
|
||||
public
|
||||
constant
|
||||
returns (
|
||||
address, //tokenAddress
|
||||
string, //name
|
||||
string, //symbol
|
||||
uint8, //decimals
|
||||
bytes, //ipfsHash
|
||||
bytes //swarmHash
|
||||
)
|
||||
{
|
||||
address _token = tokenBySymbol[_symbol];
|
||||
return getTokenMetaData(_token);
|
||||
}
|
||||
|
||||
/// @dev Returns an array containing all token addresses.
|
||||
/// @return Array of token addresses.
|
||||
function getTokenAddresses()
|
||||
public
|
||||
constant
|
||||
returns (address[])
|
||||
{
|
||||
return tokenAddresses;
|
||||
}
|
||||
}
|
115
packages/contracts/contracts/TokenTransferProxy.sol
Normal file
115
packages/contracts/contracts/TokenTransferProxy.sol
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./base/Token.sol";
|
||||
import "./base/Ownable.sol";
|
||||
|
||||
/// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract TokenTransferProxy is Ownable {
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized {
|
||||
require(authorized[msg.sender]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier targetAuthorized(address target) {
|
||||
require(authorized[target]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier targetNotAuthorized(address target) {
|
||||
require(!authorized[target]);
|
||||
_;
|
||||
}
|
||||
|
||||
mapping (address => bool) public authorized;
|
||||
address[] public authorities;
|
||||
|
||||
event LogAuthorizedAddressAdded(address indexed target, address indexed caller);
|
||||
event LogAuthorizedAddressRemoved(address indexed target, address indexed caller);
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
public
|
||||
onlyOwner
|
||||
targetNotAuthorized(target)
|
||||
{
|
||||
authorized[target] = true;
|
||||
authorities.push(target);
|
||||
LogAuthorizedAddressAdded(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
public
|
||||
onlyOwner
|
||||
targetAuthorized(target)
|
||||
{
|
||||
delete authorized[target];
|
||||
for (uint i = 0; i < authorities.length; i++) {
|
||||
if (authorities[i] == target) {
|
||||
authorities[i] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LogAuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Calls into ERC20 Token contract, invoking transferFrom.
|
||||
/// @param token Address of token to transfer.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param value Amount of token to transfer.
|
||||
/// @return Success of transfer.
|
||||
function transferFrom(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint value)
|
||||
public
|
||||
onlyAuthorized
|
||||
returns (bool)
|
||||
{
|
||||
return Token(token).transferFrom(from, to, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public constant functions
|
||||
*/
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
public
|
||||
constant
|
||||
returns (address[])
|
||||
{
|
||||
return authorities;
|
||||
}
|
||||
}
|
365
packages/contracts/contracts/base/MultiSigWallet.sol
Normal file
365
packages/contracts/contracts/base/MultiSigWallet.sol
Normal file
@@ -0,0 +1,365 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
|
||||
/// @author Stefan George - <stefan.george@consensys.net>
|
||||
contract MultiSigWallet {
|
||||
|
||||
uint constant public MAX_OWNER_COUNT = 50;
|
||||
|
||||
event Confirmation(address indexed sender, uint indexed transactionId);
|
||||
event Revocation(address indexed sender, uint indexed transactionId);
|
||||
event Submission(uint indexed transactionId);
|
||||
event Execution(uint indexed transactionId);
|
||||
event ExecutionFailure(uint indexed transactionId);
|
||||
event Deposit(address indexed sender, uint value);
|
||||
event OwnerAddition(address indexed owner);
|
||||
event OwnerRemoval(address indexed owner);
|
||||
event RequirementChange(uint required);
|
||||
|
||||
mapping (uint => Transaction) public transactions;
|
||||
mapping (uint => mapping (address => bool)) public confirmations;
|
||||
mapping (address => bool) public isOwner;
|
||||
address[] public owners;
|
||||
uint public required;
|
||||
uint public transactionCount;
|
||||
|
||||
struct Transaction {
|
||||
address destination;
|
||||
uint value;
|
||||
bytes data;
|
||||
bool executed;
|
||||
}
|
||||
|
||||
modifier onlyWallet() {
|
||||
if (msg.sender != address(this))
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier ownerDoesNotExist(address owner) {
|
||||
if (isOwner[owner])
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier ownerExists(address owner) {
|
||||
if (!isOwner[owner])
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier transactionExists(uint transactionId) {
|
||||
if (transactions[transactionId].destination == 0)
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier confirmed(uint transactionId, address owner) {
|
||||
if (!confirmations[transactionId][owner])
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notConfirmed(uint transactionId, address owner) {
|
||||
if (confirmations[transactionId][owner])
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notExecuted(uint transactionId) {
|
||||
if (transactions[transactionId].executed)
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notNull(address _address) {
|
||||
if (_address == 0)
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
modifier validRequirement(uint ownerCount, uint _required) {
|
||||
if ( ownerCount > MAX_OWNER_COUNT
|
||||
|| _required > ownerCount
|
||||
|| _required == 0
|
||||
|| ownerCount == 0)
|
||||
throw;
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Fallback function allows to deposit ether.
|
||||
function()
|
||||
payable
|
||||
{
|
||||
if (msg.value > 0)
|
||||
Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
/// @dev Contract constructor sets initial owners and required number of confirmations.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _required Number of required confirmations.
|
||||
function MultiSigWallet(address[] _owners, uint _required)
|
||||
public
|
||||
validRequirement(_owners.length, _required)
|
||||
{
|
||||
for (uint i=0; i<_owners.length; i++) {
|
||||
if (isOwner[_owners[i]] || _owners[i] == 0)
|
||||
throw;
|
||||
isOwner[_owners[i]] = true;
|
||||
}
|
||||
owners = _owners;
|
||||
required = _required;
|
||||
}
|
||||
|
||||
/// @dev Allows to add a new owner. Transaction has to be sent by wallet.
|
||||
/// @param owner Address of new owner.
|
||||
function addOwner(address owner)
|
||||
public
|
||||
onlyWallet
|
||||
ownerDoesNotExist(owner)
|
||||
notNull(owner)
|
||||
validRequirement(owners.length + 1, required)
|
||||
{
|
||||
isOwner[owner] = true;
|
||||
owners.push(owner);
|
||||
OwnerAddition(owner);
|
||||
}
|
||||
|
||||
/// @dev Allows to remove an owner. Transaction has to be sent by wallet.
|
||||
/// @param owner Address of owner.
|
||||
function removeOwner(address owner)
|
||||
public
|
||||
onlyWallet
|
||||
ownerExists(owner)
|
||||
{
|
||||
isOwner[owner] = false;
|
||||
for (uint i=0; i<owners.length - 1; i++)
|
||||
if (owners[i] == owner) {
|
||||
owners[i] = owners[owners.length - 1];
|
||||
break;
|
||||
}
|
||||
owners.length -= 1;
|
||||
if (required > owners.length)
|
||||
changeRequirement(owners.length);
|
||||
OwnerRemoval(owner);
|
||||
}
|
||||
|
||||
/// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
|
||||
/// @param owner Address of owner to be replaced.
|
||||
/// @param owner Address of new owner.
|
||||
function replaceOwner(address owner, address newOwner)
|
||||
public
|
||||
onlyWallet
|
||||
ownerExists(owner)
|
||||
ownerDoesNotExist(newOwner)
|
||||
{
|
||||
for (uint i=0; i<owners.length; i++)
|
||||
if (owners[i] == owner) {
|
||||
owners[i] = newOwner;
|
||||
break;
|
||||
}
|
||||
isOwner[owner] = false;
|
||||
isOwner[newOwner] = true;
|
||||
OwnerRemoval(owner);
|
||||
OwnerAddition(newOwner);
|
||||
}
|
||||
|
||||
/// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
|
||||
/// @param _required Number of required confirmations.
|
||||
function changeRequirement(uint _required)
|
||||
public
|
||||
onlyWallet
|
||||
validRequirement(owners.length, _required)
|
||||
{
|
||||
required = _required;
|
||||
RequirementChange(_required);
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to submit and confirm a transaction.
|
||||
/// @param destination Transaction target address.
|
||||
/// @param value Transaction ether value.
|
||||
/// @param data Transaction data payload.
|
||||
/// @return Returns transaction ID.
|
||||
function submitTransaction(address destination, uint value, bytes data)
|
||||
public
|
||||
returns (uint transactionId)
|
||||
{
|
||||
transactionId = addTransaction(destination, value, data);
|
||||
confirmTransaction(transactionId);
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to confirm a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function confirmTransaction(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
transactionExists(transactionId)
|
||||
notConfirmed(transactionId, msg.sender)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = true;
|
||||
Confirmation(msg.sender, transactionId);
|
||||
executeTransaction(transactionId);
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to revoke a confirmation for a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function revokeConfirmation(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
confirmed(transactionId, msg.sender)
|
||||
notExecuted(transactionId)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = false;
|
||||
Revocation(msg.sender, transactionId);
|
||||
}
|
||||
|
||||
/// @dev Allows anyone to execute a confirmed transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeTransaction(uint transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
{
|
||||
if (isConfirmed(transactionId)) {
|
||||
Transaction tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Returns the confirmation status of a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
/// @return Confirmation status.
|
||||
function isConfirmed(uint transactionId)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
uint count = 0;
|
||||
for (uint i=0; i<owners.length; i++) {
|
||||
if (confirmations[transactionId][owners[i]])
|
||||
count += 1;
|
||||
if (count == required)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
/// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
|
||||
/// @param destination Transaction target address.
|
||||
/// @param value Transaction ether value.
|
||||
/// @param data Transaction data payload.
|
||||
/// @return Returns transaction ID.
|
||||
function addTransaction(address destination, uint value, bytes data)
|
||||
internal
|
||||
notNull(destination)
|
||||
returns (uint transactionId)
|
||||
{
|
||||
transactionId = transactionCount;
|
||||
transactions[transactionId] = Transaction({
|
||||
destination: destination,
|
||||
value: value,
|
||||
data: data,
|
||||
executed: false
|
||||
});
|
||||
transactionCount += 1;
|
||||
Submission(transactionId);
|
||||
}
|
||||
|
||||
/*
|
||||
* Web3 call functions
|
||||
*/
|
||||
/// @dev Returns number of confirmations of a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
/// @return Number of confirmations.
|
||||
function getConfirmationCount(uint transactionId)
|
||||
public
|
||||
constant
|
||||
returns (uint count)
|
||||
{
|
||||
for (uint i=0; i<owners.length; i++)
|
||||
if (confirmations[transactionId][owners[i]])
|
||||
count += 1;
|
||||
}
|
||||
|
||||
/// @dev Returns total number of transactions after filers are applied.
|
||||
/// @param pending Include pending transactions.
|
||||
/// @param executed Include executed transactions.
|
||||
/// @return Total number of transactions after filters are applied.
|
||||
function getTransactionCount(bool pending, bool executed)
|
||||
public
|
||||
constant
|
||||
returns (uint count)
|
||||
{
|
||||
for (uint i=0; i<transactionCount; i++)
|
||||
if ( pending && !transactions[i].executed
|
||||
|| executed && transactions[i].executed)
|
||||
count += 1;
|
||||
}
|
||||
|
||||
/// @dev Returns list of owners.
|
||||
/// @return List of owner addresses.
|
||||
function getOwners()
|
||||
public
|
||||
constant
|
||||
returns (address[])
|
||||
{
|
||||
return owners;
|
||||
}
|
||||
|
||||
/// @dev Returns array with owner addresses, which confirmed transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
/// @return Returns array of owner addresses.
|
||||
function getConfirmations(uint transactionId)
|
||||
public
|
||||
constant
|
||||
returns (address[] _confirmations)
|
||||
{
|
||||
address[] memory confirmationsTemp = new address[](owners.length);
|
||||
uint count = 0;
|
||||
uint i;
|
||||
for (i=0; i<owners.length; i++)
|
||||
if (confirmations[transactionId][owners[i]]) {
|
||||
confirmationsTemp[count] = owners[i];
|
||||
count += 1;
|
||||
}
|
||||
_confirmations = new address[](count);
|
||||
for (i=0; i<count; i++)
|
||||
_confirmations[i] = confirmationsTemp[i];
|
||||
}
|
||||
|
||||
/// @dev Returns list of transaction IDs in defined range.
|
||||
/// @param from Index start position of transaction array.
|
||||
/// @param to Index end position of transaction array.
|
||||
/// @param pending Include pending transactions.
|
||||
/// @param executed Include executed transactions.
|
||||
/// @return Returns array of transaction IDs.
|
||||
function getTransactionIds(uint from, uint to, bool pending, bool executed)
|
||||
public
|
||||
constant
|
||||
returns (uint[] _transactionIds)
|
||||
{
|
||||
uint[] memory transactionIdsTemp = new uint[](transactionCount);
|
||||
uint count = 0;
|
||||
uint i;
|
||||
for (i=0; i<transactionCount; i++)
|
||||
if ( pending && !transactions[i].executed
|
||||
|| executed && transactions[i].executed)
|
||||
{
|
||||
transactionIdsTemp[count] = i;
|
||||
count += 1;
|
||||
}
|
||||
_transactionIds = new uint[](to - from);
|
||||
for (i=from; i<to; i++)
|
||||
_transactionIds[i - from] = transactionIdsTemp[i];
|
||||
}
|
||||
}
|
27
packages/contracts/contracts/base/Ownable.sol
Normal file
27
packages/contracts/contracts/base/Ownable.sol
Normal file
@@ -0,0 +1,27 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
/*
|
||||
* Ownable
|
||||
*
|
||||
* Base contract with an owner.
|
||||
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
|
||||
*/
|
||||
|
||||
contract Ownable {
|
||||
address public owner;
|
||||
|
||||
function Ownable() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner);
|
||||
_;
|
||||
}
|
||||
|
||||
function transferOwnership(address newOwner) onlyOwner {
|
||||
if (newOwner != address(0)) {
|
||||
owner = newOwner;
|
||||
}
|
||||
}
|
||||
}
|
41
packages/contracts/contracts/base/SafeMath.sol
Normal file
41
packages/contracts/contracts/base/SafeMath.sol
Normal file
@@ -0,0 +1,41 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
contract SafeMath {
|
||||
function safeMul(uint a, uint b) internal constant returns (uint256) {
|
||||
uint c = a * b;
|
||||
assert(a == 0 || c / a == b);
|
||||
return c;
|
||||
}
|
||||
|
||||
function safeDiv(uint a, uint b) internal constant returns (uint256) {
|
||||
uint c = a / b;
|
||||
return c;
|
||||
}
|
||||
|
||||
function safeSub(uint a, uint b) internal constant returns (uint256) {
|
||||
assert(b <= a);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
function safeAdd(uint a, uint b) internal constant returns (uint256) {
|
||||
uint c = a + b;
|
||||
assert(c >= a);
|
||||
return c;
|
||||
}
|
||||
|
||||
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
}
|
44
packages/contracts/contracts/base/StandardToken.sol
Normal file
44
packages/contracts/contracts/base/StandardToken.sol
Normal file
@@ -0,0 +1,44 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
import "./Token.sol";
|
||||
|
||||
contract StandardToken is Token {
|
||||
|
||||
function transfer(address _to, uint _value) returns (bool) {
|
||||
//Default assumes totalSupply can't be over max (2^256 - 1).
|
||||
if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
balances[msg.sender] -= _value;
|
||||
balances[_to] += _value;
|
||||
Transfer(msg.sender, _to, _value);
|
||||
return true;
|
||||
} else { return false; }
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint _value) returns (bool) {
|
||||
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
Transfer(_from, _to, _value);
|
||||
return true;
|
||||
} else { return false; }
|
||||
}
|
||||
|
||||
function balanceOf(address _owner) constant returns (uint) {
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function approve(address _spender, uint _value) returns (bool) {
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
Approval(msg.sender, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender) constant returns (uint) {
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
|
||||
mapping (address => uint) balances;
|
||||
mapping (address => mapping (address => uint)) allowed;
|
||||
uint public totalSupply;
|
||||
}
|
38
packages/contracts/contracts/base/Token.sol
Normal file
38
packages/contracts/contracts/base/Token.sol
Normal file
@@ -0,0 +1,38 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
contract Token {
|
||||
|
||||
/// @return total amount of tokens
|
||||
function totalSupply() constant returns (uint supply) {}
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return The balance
|
||||
function balanceOf(address _owner) constant returns (uint balance) {}
|
||||
|
||||
/// @notice send `_value` token to `_to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transfer(address _to, uint _value) returns (bool success) {}
|
||||
|
||||
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
|
||||
/// @param _from The address of the sender
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transferFrom(address _from, address _to, uint _value) returns (bool success) {}
|
||||
|
||||
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of wei to be approved for transfer
|
||||
/// @return Whether the approval was successful or not
|
||||
function approve(address _spender, uint _value) returns (bool success) {}
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender) constant returns (uint remaining) {}
|
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint _value);
|
||||
}
|
33
packages/contracts/contracts/test/DummyToken.sol
Normal file
33
packages/contracts/contracts/test/DummyToken.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
import "./Mintable.sol";
|
||||
import "./../base/Ownable.sol";
|
||||
|
||||
contract DummyToken is Mintable, Ownable {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint public decimals;
|
||||
|
||||
function DummyToken(
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint _decimals,
|
||||
uint _totalSupply)
|
||||
{
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
totalSupply = _totalSupply;
|
||||
balances[msg.sender] = _totalSupply;
|
||||
}
|
||||
|
||||
function setBalance(address _target, uint _value) onlyOwner {
|
||||
uint currBalance = balanceOf(_target);
|
||||
if (_value < currBalance) {
|
||||
totalSupply = safeSub(totalSupply, safeSub(currBalance, _value));
|
||||
} else {
|
||||
totalSupply = safeAdd(totalSupply, safeSub(_value, currBalance));
|
||||
}
|
||||
balances[_target] = _value;
|
||||
}
|
||||
}
|
29
packages/contracts/contracts/test/MaliciousToken.sol
Normal file
29
packages/contracts/contracts/test/MaliciousToken.sol
Normal file
@@ -0,0 +1,29 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
import "./../base/StandardToken.sol";
|
||||
|
||||
contract MaliciousToken is StandardToken {
|
||||
uint8 stateToUpdate = 1; // Not null so that change only requires 5000 gas
|
||||
|
||||
function updateState() internal {
|
||||
stateToUpdate++;
|
||||
}
|
||||
|
||||
function balanceOf(address _owner)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
updateState();
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
updateState();
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
}
|
16
packages/contracts/contracts/test/Mintable.sol
Normal file
16
packages/contracts/contracts/test/Mintable.sol
Normal file
@@ -0,0 +1,16 @@
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
import "./../tokens/UnlimitedAllowanceToken.sol";
|
||||
import "./../base/SafeMath.sol";
|
||||
|
||||
/*
|
||||
* Mintable
|
||||
* Base contract that creates a mintable UnlimitedAllowanceToken
|
||||
*/
|
||||
contract Mintable is UnlimitedAllowanceToken, SafeMath {
|
||||
function mint(uint _value) {
|
||||
require(_value <= 100000000000000000000);
|
||||
balances[msg.sender] = safeAdd(_value, balances[msg.sender]);
|
||||
totalSupply = safeAdd(totalSupply, _value);
|
||||
}
|
||||
}
|
56
packages/contracts/contracts/tokens/EtherToken.sol
Normal file
56
packages/contracts/contracts/tokens/EtherToken.sol
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./UnlimitedAllowanceToken.sol";
|
||||
import "./../base/SafeMath.sol";
|
||||
|
||||
contract EtherToken is UnlimitedAllowanceToken, SafeMath {
|
||||
|
||||
string constant public name = "Ether Token";
|
||||
string constant public symbol = "WETH";
|
||||
uint8 constant public decimals = 18;
|
||||
|
||||
/// @dev Fallback to calling deposit when ether is sent directly to contract.
|
||||
function()
|
||||
public
|
||||
payable
|
||||
{
|
||||
deposit();
|
||||
}
|
||||
|
||||
/// @dev Buys tokens with Ether, exchanging them 1:1.
|
||||
function deposit()
|
||||
public
|
||||
payable
|
||||
{
|
||||
balances[msg.sender] = safeAdd(balances[msg.sender], msg.value);
|
||||
totalSupply = safeAdd(totalSupply, msg.value);
|
||||
}
|
||||
|
||||
/// @dev Sells tokens in exchange for Ether, exchanging them 1:1.
|
||||
/// @param amount Number of tokens to sell.
|
||||
function withdraw(uint amount)
|
||||
public
|
||||
{
|
||||
balances[msg.sender] = safeSub(balances[msg.sender], amount);
|
||||
totalSupply = safeSub(totalSupply, amount);
|
||||
require(msg.sender.send(amount));
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./../base/StandardToken.sol";
|
||||
|
||||
contract UnlimitedAllowanceToken is StandardToken {
|
||||
|
||||
uint constant MAX_UINT = 2**256 - 1;
|
||||
|
||||
/// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
|
||||
/// @param _from Address to transfer from.
|
||||
/// @param _to Address to transfer to.
|
||||
/// @param _value Amount to transfer.
|
||||
/// @return Success of transfer.
|
||||
function transferFrom(address _from, address _to, uint _value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
uint allowance = allowed[_from][msg.sender];
|
||||
if (balances[_from] >= _value
|
||||
&& allowance >= _value
|
||||
&& balances[_to] + _value >= balances[_to]
|
||||
) {
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
if (allowance < MAX_UINT) {
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
}
|
||||
Transfer(_from, _to, _value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
33
packages/contracts/contracts/tokens/ZRXToken.sol
Normal file
33
packages/contracts/contracts/tokens/ZRXToken.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 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.4.11;
|
||||
|
||||
import "./UnlimitedAllowanceToken.sol";
|
||||
|
||||
contract ZRXToken is UnlimitedAllowanceToken {
|
||||
|
||||
uint8 constant public decimals = 18;
|
||||
uint public totalSupply = 10**27; // 1 billion tokens, 18 decimal places
|
||||
string constant public name = "0x Protocol Token";
|
||||
string constant public symbol = "ZRX";
|
||||
|
||||
function ZRXToken() {
|
||||
balances[msg.sender] = totalSupply;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user