Asset Proxy Dispatcher
This commit is contained in:
committed by
Amir Bandeali
parent
b9e0cd4512
commit
78d81f193f
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./IAssetProxyDispatcher.sol";
|
||||
import "./IAssetProxy.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "../../utils/Authorizable/Authorizable.sol";
|
||||
|
||||
contract AssetProxyDispatcher is
|
||||
Ownable,
|
||||
Authorizable,
|
||||
IAssetProxyDispatcher
|
||||
{
|
||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||
mapping (uint8 => IAssetProxy) public assetProxies;
|
||||
|
||||
/// @dev Delegates transfer to the corresponding asset proxy.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
// Lookup asset proxy
|
||||
require(assetMetadata.length >= 1);
|
||||
uint8 assetProxyId = uint8(assetMetadata[0]);
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// Dispatch transfer to asset proxy
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetMetadata, from, to, amount);
|
||||
}
|
||||
|
||||
/// @dev Registers a new asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @param newAssetProxyAddress Address of the asset proxy contract to register.
|
||||
/// @param currentAssetProxyAddress Address of existing asset proxy to overwrite.
|
||||
function setAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxyAddress,
|
||||
address currentAssetProxyAddress)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
// Ensure any existing asset proxy is not unintentionally overwritten
|
||||
require(currentAssetProxyAddress == address(assetProxies[assetProxyId]));
|
||||
|
||||
// Store asset proxy and log registration
|
||||
assetProxies[assetProxyId] = IAssetProxy(newAssetProxyAddress);
|
||||
emit AssetProxyChanged(assetProxyId, newAssetProxyAddress, currentAssetProxyAddress);
|
||||
}
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
public view
|
||||
returns (IAssetProxy)
|
||||
{
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
return assetProxy;
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
contract IAssetProxy {
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public;
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./IAssetProxy.sol";
|
||||
import "../../utils/Authorizable/IAuthorizable.sol";
|
||||
|
||||
contract IAssetProxyDispatcher is
|
||||
IAuthorizable,
|
||||
IAssetProxy
|
||||
{
|
||||
// Logs registration of new asset proxy
|
||||
event AssetProxyChanged(
|
||||
uint8 id,
|
||||
address newAssetClassAddress,
|
||||
address oldAssetClassAddress
|
||||
);
|
||||
|
||||
/// @dev Sets a new asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @param newAssetProxyAddress Address of the asset proxy contract to register.
|
||||
/// @param currentAssetProxyAddress Address of existing asset proxy to overwrite.
|
||||
function setAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxyAddress,
|
||||
address currentAssetProxyAddress)
|
||||
public;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
public view
|
||||
returns (IAssetProxy);
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../IAssetProxy.sol";
|
||||
import "../../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../../utils/Authorizable/Authorizable.sol";
|
||||
import { Token_v1 as ERC20Token } from "../../../../previous/Token/Token_v1.sol";
|
||||
|
||||
contract ERC20TransferProxy is
|
||||
LibBytes,
|
||||
Authorizable,
|
||||
IAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Transfers ERC20 tokens.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
address token = decodeMetadata(assetMetadata);
|
||||
bool success = ERC20Token(token).transferFrom(from, to, amount);
|
||||
require(success == true);
|
||||
}
|
||||
|
||||
/// @dev Encodes ERC20 byte array for the ERC20 asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @param tokenAddress Address of the asset.
|
||||
/// @return assetMetadata Byte array encoded for the ERC20 asset proxy.
|
||||
function encodeMetadata(
|
||||
uint8 assetProxyId,
|
||||
address tokenAddress)
|
||||
public pure
|
||||
returns (bytes assetMetadata)
|
||||
{
|
||||
// 0 is reserved as invalid proxy id
|
||||
require(assetProxyId != 0);
|
||||
|
||||
// Encode fields into a byte array
|
||||
assetMetadata = new bytes(21);
|
||||
assetMetadata[0] = byte(assetProxyId);
|
||||
writeAddress(tokenAddress, assetMetadata, 1);
|
||||
return assetMetadata;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20-encoded byte array for the ERC20 asset proxy.
|
||||
/// @param assetMetadata Byte array encoded for the ERC20 asset proxy.
|
||||
/// @return tokenAddress Address of ERC20 token.
|
||||
function decodeMetadata(bytes assetMetadata)
|
||||
public pure
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
require(assetMetadata.length == 21);
|
||||
return readAddress(assetMetadata, 1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../IAssetProxy.sol";
|
||||
import "../../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../TokenTransferProxy/ITokenTransferProxy.sol";
|
||||
import "../../../utils/Authorizable/Authorizable.sol";
|
||||
|
||||
contract ERC20TransferProxy_v1 is
|
||||
LibBytes,
|
||||
Authorizable,
|
||||
IAssetProxy
|
||||
{
|
||||
ITokenTransferProxy TRANSFER_PROXY;
|
||||
|
||||
/// @dev Contract constructor.
|
||||
/// @param tokenTransferProxyContract erc20 token transfer proxy contract.
|
||||
function ERC20TransferProxy_v1(ITokenTransferProxy tokenTransferProxyContract)
|
||||
public
|
||||
{
|
||||
TRANSFER_PROXY = tokenTransferProxyContract;
|
||||
}
|
||||
|
||||
/// @dev Transfers ERC20 tokens.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
address token = decodeMetadata(assetMetadata);
|
||||
bool success = TRANSFER_PROXY.transferFrom(token, from, to, amount);
|
||||
require(success == true);
|
||||
}
|
||||
|
||||
/// @dev Encodes ERC20 byte array for the ERC20 asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @param tokenAddress Address of the asset.
|
||||
/// @return assetMetadata Byte array encoded for the ERC20 asset proxy.
|
||||
function encodeMetadata(
|
||||
uint8 assetProxyId,
|
||||
address tokenAddress)
|
||||
public pure
|
||||
returns (bytes assetMetadata)
|
||||
{
|
||||
// 0 is reserved as invalid proxy id
|
||||
require(assetProxyId != 0);
|
||||
|
||||
// Encode fields into a byte array
|
||||
assetMetadata = new bytes(21);
|
||||
assetMetadata[0] = byte(assetProxyId);
|
||||
writeAddress(tokenAddress, assetMetadata, 1);
|
||||
return assetMetadata;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20-encoded byte array for the ERC20 asset proxy.
|
||||
/// @param assetMetadata Byte array encoded for the ERC20 asset proxy.
|
||||
/// @return tokenAddress Address of ERC20 token.
|
||||
function decodeMetadata(bytes assetMetadata)
|
||||
public pure
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
require(assetMetadata.length == 21);
|
||||
return readAddress(assetMetadata, 1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../IAssetProxy.sol";
|
||||
import "../../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../../utils/Authorizable/Authorizable.sol";
|
||||
import "/zeppelin/contracts/token/ERC721/ERC721Token.sol";
|
||||
|
||||
|
||||
contract ERC721TransferProxy is
|
||||
LibBytes,
|
||||
Authorizable,
|
||||
IAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Transfers ERC20 tokens.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
// Decode metadata
|
||||
address token;
|
||||
uint256 tokenId;
|
||||
(token, tokenId) = decodeMetadata(assetMetadata);
|
||||
|
||||
// There exists only 1 of each token.
|
||||
require(amount == 1);
|
||||
|
||||
// Call ERC721 contract. Either succeeds or throws.
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
|
||||
/// @dev Encodes ERC721 byte array for the ERC20 asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @param tokenAddress Address of the asset.
|
||||
/// @param tokenId Id of ERC721 token.
|
||||
/// @return assetMetadata Byte array encoded for the ERC721 asset proxy.
|
||||
function encodeMetadata(
|
||||
uint8 assetProxyId,
|
||||
address tokenAddress,
|
||||
uint256 tokenId)
|
||||
public pure
|
||||
returns (bytes assetMetadata)
|
||||
{
|
||||
// 0 is reserved as invalid proxy id
|
||||
require(assetProxyId != 0);
|
||||
|
||||
// Encode fields into a byte array
|
||||
assetMetadata = new bytes(53);
|
||||
assetMetadata[0] = byte(assetProxyId);
|
||||
writeAddress(tokenAddress, assetMetadata, 1);
|
||||
writeUint256(tokenId, assetMetadata, 21);
|
||||
return assetMetadata;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721-encoded byte array for the ERC721 asset proxy.
|
||||
/// @param assetMetadata Byte array encoded for the ERC721 asset proxy.
|
||||
/// @return tokenAddress Address of ERC721 token.
|
||||
/// @return tokenId Id of ERC721 token.
|
||||
function decodeMetadata(bytes assetMetadata)
|
||||
public pure
|
||||
returns (address tokenAddress, uint256 tokenId)
|
||||
{
|
||||
require(assetMetadata.length == 53);
|
||||
tokenAddress = readAddress(assetMetadata, 1);
|
||||
tokenId = readUint256(assetMetadata, 21);
|
||||
return (tokenAddress, tokenId);
|
||||
}
|
||||
}
|
@@ -23,6 +23,8 @@ import "./MixinExchangeCore.sol";
|
||||
import "./MixinSignatureValidator.sol";
|
||||
import "./MixinSettlementProxy.sol";
|
||||
import "./MixinWrapperFunctions.sol";
|
||||
import "../AssetProxyDispatcher/IAssetProxyDispatcher.sol";
|
||||
import "../TokenTransferProxy/ITokenTransferProxy.sol";
|
||||
|
||||
contract Exchange is
|
||||
MixinExchangeCore,
|
||||
@@ -34,11 +36,12 @@ contract Exchange is
|
||||
|
||||
function Exchange(
|
||||
IToken _zrxToken,
|
||||
ITokenTransferProxy _tokenTransferProxy)
|
||||
bytes _zrxProxyMetadata,
|
||||
IAssetProxyDispatcher _assetProxyDispatcher)
|
||||
public
|
||||
MixinExchangeCore()
|
||||
MixinSignatureValidator()
|
||||
MixinSettlementProxy(_tokenTransferProxy, _zrxToken)
|
||||
MixinSettlementProxy(_assetProxyDispatcher, _zrxToken, _zrxProxyMetadata)
|
||||
MixinWrapperFunctions()
|
||||
{}
|
||||
}
|
||||
|
@@ -54,11 +54,6 @@ contract IExchange {
|
||||
bytes32 indexed orderHash
|
||||
);
|
||||
|
||||
event LogCancelBefore(
|
||||
address indexed maker,
|
||||
uint256 salt
|
||||
);
|
||||
|
||||
function ZRX_TOKEN_CONTRACT()
|
||||
public view
|
||||
returns (address);
|
||||
|
@@ -33,7 +33,9 @@ contract LibOrder {
|
||||
"uint256 makerFee",
|
||||
"uint256 takerFee",
|
||||
"uint256 expirationTimeSeconds",
|
||||
"uint256 salt"
|
||||
"uint256 salt",
|
||||
"bytes makerAssetProxyData",
|
||||
"bytes takerAssetProxyData"
|
||||
);
|
||||
|
||||
struct Order {
|
||||
@@ -48,6 +50,8 @@ contract LibOrder {
|
||||
uint256 takerFee;
|
||||
uint256 expirationTimeSeconds;
|
||||
uint256 salt;
|
||||
bytes makerAssetProxyData;
|
||||
bytes takerAssetProxyData;
|
||||
}
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of the order.
|
||||
@@ -73,7 +77,9 @@ contract LibOrder {
|
||||
order.makerFee,
|
||||
order.takerFee,
|
||||
order.expirationTimeSeconds,
|
||||
order.salt
|
||||
order.salt,
|
||||
order.makerAssetProxyData,
|
||||
order.takerAssetProxyData
|
||||
)
|
||||
);
|
||||
return orderHash;
|
||||
|
@@ -36,5 +36,3 @@ contract LibPartialAmount is SafeMath {
|
||||
return partialAmount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -20,22 +20,22 @@ pragma solidity ^0.4.21;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "../TokenTransferProxy/ITokenTransferProxy.sol";
|
||||
import "../../tokens/Token/IToken.sol";
|
||||
import "./LibPartialAmount.sol";
|
||||
import "../AssetProxyDispatcher/IAssetProxyDispatcher.sol";
|
||||
|
||||
/// @dev Provides MixinSettlement
|
||||
contract MixinSettlementProxy is
|
||||
MSettlement,
|
||||
LibPartialAmount
|
||||
{
|
||||
|
||||
ITokenTransferProxy TRANSFER_PROXY;
|
||||
IAssetProxyDispatcher TRANSFER_PROXY;
|
||||
bytes ZRX_PROXY_METADATA;
|
||||
IToken ZRX_TOKEN;
|
||||
|
||||
function transferProxy()
|
||||
external view
|
||||
returns (ITokenTransferProxy)
|
||||
public view
|
||||
returns (IAssetProxyDispatcher)
|
||||
{
|
||||
return TRANSFER_PROXY;
|
||||
}
|
||||
@@ -47,15 +47,26 @@ contract MixinSettlementProxy is
|
||||
return ZRX_TOKEN;
|
||||
}
|
||||
|
||||
function zrxProxyMetadata()
|
||||
external view
|
||||
returns (bytes)
|
||||
{
|
||||
return ZRX_PROXY_METADATA;
|
||||
}
|
||||
|
||||
function MixinSettlementProxy(
|
||||
ITokenTransferProxy _proxyContract,
|
||||
IToken _zrxToken)
|
||||
IAssetProxyDispatcher assetProxyDispatcherContract,
|
||||
IToken zrxToken,
|
||||
bytes zrxProxyMetadata)
|
||||
public
|
||||
{
|
||||
ZRX_TOKEN = _zrxToken;
|
||||
TRANSFER_PROXY = _proxyContract;
|
||||
ZRX_TOKEN = zrxToken;
|
||||
TRANSFER_PROXY = assetProxyDispatcherContract;
|
||||
ZRX_PROXY_METADATA = zrxProxyMetadata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function settleOrder(
|
||||
Order memory order,
|
||||
address takerAddress,
|
||||
@@ -68,43 +79,35 @@ contract MixinSettlementProxy is
|
||||
)
|
||||
{
|
||||
makerTokenFilledAmount = getPartialAmount(takerTokenFilledAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
require(
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
order.makerTokenAddress,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
makerTokenFilledAmount
|
||||
)
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
order.makerAssetProxyData,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
makerTokenFilledAmount
|
||||
);
|
||||
require(
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
order.takerTokenAddress,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
takerTokenFilledAmount
|
||||
)
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
order.takerAssetProxyData,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
takerTokenFilledAmount
|
||||
);
|
||||
if (order.feeRecipientAddress != address(0)) {
|
||||
if (order.makerFee > 0) {
|
||||
makerFeePaid = getPartialAmount(takerTokenFilledAmount, order.takerTokenAmount, order.makerFee);
|
||||
require(
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
ZRX_TOKEN,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
makerFeePaid
|
||||
)
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
ZRX_PROXY_METADATA,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
makerFeePaid
|
||||
);
|
||||
}
|
||||
if (order.takerFee > 0) {
|
||||
takerFeePaid = getPartialAmount(takerTokenFilledAmount, order.takerTokenAmount, order.takerFee);
|
||||
require(
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
ZRX_TOKEN,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
takerFeePaid
|
||||
)
|
||||
TRANSFER_PROXY.transferFrom(
|
||||
ZRX_PROXY_METADATA,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
takerFeePaid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -65,76 +65,163 @@ contract MixinWrapperFunctions is
|
||||
// We need to call MExchangeCore.fillOrder using a delegatecall in
|
||||
// assembly so that we can intercept a call that throws. For this, we
|
||||
// need the input encoded in memory in the Ethereum ABIv2 format [1].
|
||||
|
||||
// | Offset | Length | Contents |
|
||||
// |--------|---------|------------------------------|
|
||||
// | 0 | 4 | function selector |
|
||||
// | 4 | 11 * 32 | Order order |
|
||||
// | 356 | 32 | uint256 takerTokenFillAmount |
|
||||
// | 388 | 32 | offset to signature (416) |
|
||||
// | 420 | 32 | len(signature) |
|
||||
// | 452 | (1) | signature |
|
||||
// | (2) | (3) | padding (zero) |
|
||||
// | (4) | | end of input |
|
||||
|
||||
// (1): len(signature)
|
||||
// (2): 452 + len(signature)
|
||||
// (3): (32 - len(signature)) mod 32
|
||||
// (4): 452 + len(signature) + (32 - len(signature)) mod 32
|
||||
|
||||
|
||||
// | Area | Offset | Length | Contents |
|
||||
// | -------- |--------|---------|-------------------------------------------- |
|
||||
// | Header | 0x00 | 4 | function selector |
|
||||
// | Params | | 3 * 32 | function parameters: |
|
||||
// | | 0x00 | | 1. offset to order (*) |
|
||||
// | | 0x20 | | 2. takerTokenFillAmount |
|
||||
// | | 0x40 | | 3. offset to signature (*) |
|
||||
// | Data | | 13 * 32 | order: |
|
||||
// | | 0x000 | | 1. makerAddress |
|
||||
// | | 0x020 | | 2. takerAddress |
|
||||
// | | 0x040 | | 3. makerTokenAddress |
|
||||
// | | 0x060 | | 4. takerTokenAddress |
|
||||
// | | 0x080 | | 5. feeRecipientAddress |
|
||||
// | | 0x0A0 | | 6. makerTokenAmount |
|
||||
// | | 0x0C0 | | 7. takerTokenAmount |
|
||||
// | | 0x0E0 | | 8. makerFeeAmount |
|
||||
// | | 0x100 | | 9. takerFeeAmount |
|
||||
// | | 0x120 | | 10. expirationTimeSeconds |
|
||||
// | | 0x140 | | 11. salt |
|
||||
// | | 0x160 | | 12. Offset to makerAssetProxyMetadata (*) |
|
||||
// | | 0x180 | | 13. Offset to takerAssetProxyMetadata (* |
|
||||
// | | 0x1A0 | 32 | makerAssetProxyMetadata Length |
|
||||
// | | 0x1C0 | ** | makerAssetProxyMetadata Contents |
|
||||
// | | 0x1E0 | 32 | takerAssetProxyMetadata Length |
|
||||
// | | 0x200 | ** | takerAssetProxyMetadata Contents |
|
||||
// | | 0x220 | 32 | signature Length |
|
||||
// | | 0x240 | ** | signature Contents |
|
||||
|
||||
// * Offsets are calculated from the beginning of the current area: Header, Params, Data:
|
||||
// An offset stored in the Params area is calculated from the beginning of the Params section.
|
||||
// An offset stored in the Data area is calculated from the beginning of the Data section.
|
||||
|
||||
// ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
|
||||
|
||||
// [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
|
||||
|
||||
bytes4 fillOrderSelector = this.fillOrder.selector;
|
||||
|
||||
assembly {
|
||||
|
||||
// Areas below may use the following variables:
|
||||
// 1. <area>Start -- Start of this area in memory
|
||||
// 2. <area>End -- End of this area in memory. This value may
|
||||
// be precomputed (before writing contents),
|
||||
// or it may be computed as contents are written.
|
||||
// 3. <area>Offset -- Current offset into area. If an area's End
|
||||
// is precomputed, this variable tracks the
|
||||
// offsets of contents as they are written.
|
||||
|
||||
/////// Setup Header Area ///////
|
||||
// Load free memory pointer
|
||||
let start := mload(0x40)
|
||||
let headerAreaStart := mload(0x40)
|
||||
mstore(headerAreaStart, fillOrderSelector)
|
||||
let headerAreaEnd := add(headerAreaStart, 0x4)
|
||||
|
||||
// Write function signature
|
||||
mstore(start, fillOrderSelector)
|
||||
/////// Setup Params Area ///////
|
||||
// This area is preallocated and written to later.
|
||||
// This is because we need to fill in offsets that have not yet been calculated.
|
||||
let paramsAreaStart := headerAreaEnd
|
||||
let paramsAreaEnd := add(paramsAreaStart, 0x60)
|
||||
let paramsAreaOffset := paramsAreaStart
|
||||
|
||||
// Write order struct
|
||||
mstore(add(start, 4), mload(order)) // makerAddress
|
||||
mstore(add(start, 36), mload(add(order, 32))) // takerAddress
|
||||
mstore(add(start, 68), mload(add(order, 64))) // makerTokenAddress
|
||||
mstore(add(start, 100), mload(add(order, 96))) // takerTokenAddress
|
||||
mstore(add(start, 132), mload(add(order, 128))) // feeRecipientAddress
|
||||
mstore(add(start, 164), mload(add(order, 160))) // makerTokenAmount
|
||||
mstore(add(start, 196), mload(add(order, 192))) // takerTokenAmount
|
||||
mstore(add(start, 228), mload(add(order, 224))) // makerFeeAmount
|
||||
mstore(add(start, 260), mload(add(order, 256))) // takerFeeAmount
|
||||
mstore(add(start, 292), mload(add(order, 288))) // expirationTimeSeconds
|
||||
mstore(add(start, 324), mload(add(order, 320))) // salt
|
||||
/////// Setup Data Area ///////
|
||||
let dataAreaStart := paramsAreaEnd
|
||||
let dataAreaEnd := dataAreaStart
|
||||
|
||||
// Write takerTokenFillAmount
|
||||
mstore(add(start, 356), takerTokenFillAmount)
|
||||
// Offset from the source data we're reading from
|
||||
let sourceOffset := order
|
||||
// bytesLen and bytesLenPadded track the length of a dynamically-allocated bytes array.
|
||||
let bytesLen := 0
|
||||
let bytesLenPadded := 0
|
||||
|
||||
// Write signature offset
|
||||
mstore(add(start, 388), 416)
|
||||
/////// Write order Struct ///////
|
||||
// Write memory location of Order, relative to the start of the
|
||||
// parameter list, then increment the paramsAreaOffset respectively.
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
// Write signature length
|
||||
let sigLen := mload(signature)
|
||||
mstore(add(start, 420), sigLen)
|
||||
// Write values for each field in the order
|
||||
for{let i := 0} lt(i, 13) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Calculate signature length with padding
|
||||
let paddingLen := mod(sub(0, sigLen), 32)
|
||||
let sigLenWithPadding := add(sigLen, paddingLen)
|
||||
// Write offset to <order.makerAssetProxyMetadata>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Write signature
|
||||
let sigStart := add(signature, 32)
|
||||
for { let curr := 0 }
|
||||
lt(curr, sigLenWithPadding)
|
||||
{ curr := add(curr, 32) }
|
||||
{ mstore(add(start, add(452, curr)), mload(add(sigStart, curr))) } // Note: we assume that padding consists of only 0's
|
||||
// Calculate length of <order.makerAssetProxyMetadata>
|
||||
bytesLen := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
bytesLenPadded := add(div(bytesLen, 0x20), gt(mod(bytesLen, 0x20), 0))
|
||||
|
||||
// Write length of <order.makerAssetProxyMetadata>
|
||||
mstore(dataAreaEnd, bytesLen)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetProxyMetadata>
|
||||
for {let i := 0} lt(i, bytesLenPadded) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Write offset to <order.takerAssetProxyMetadata>
|
||||
mstore(add(dataAreaStart, mul(12, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetProxyMetadata>
|
||||
bytesLen := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
bytesLenPadded := add(div(bytesLen, 0x20), gt(mod(bytesLen, 0x20), 0))
|
||||
|
||||
// Write length of <order.takerAssetProxyMetadata>
|
||||
mstore(dataAreaEnd, bytesLen)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetProxyMetadata>
|
||||
for {let i := 0} lt(i, bytesLenPadded) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
/////// Write takerTokenFillAmount ///////
|
||||
mstore(paramsAreaOffset, takerTokenFillAmount)
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
/////// Write signature ///////
|
||||
// Write offset to paramsArea
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
|
||||
// Calculate length of signature
|
||||
sourceOffset := signature
|
||||
bytesLen := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
bytesLenPadded := add(div(bytesLen, 0x20), gt(mod(bytesLen, 0x20), 0))
|
||||
|
||||
// Write length of signature
|
||||
mstore(dataAreaEnd, bytesLen)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of signature
|
||||
for {let i := 0} lt(i, bytesLenPadded) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Execute delegatecall
|
||||
let success := delegatecall(
|
||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||
address, // call address of this contract
|
||||
start, // pointer to start of input
|
||||
add(452, sigLenWithPadding), // input length is 420 + signature length + padding length
|
||||
start, // write output over input
|
||||
128 // output size is 128 bytes
|
||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||
address, // call address of this contract
|
||||
headerAreaStart, // pointer to start of input
|
||||
sub(dataAreaEnd, headerAreaStart), // length of input
|
||||
headerAreaStart, // write output over input
|
||||
128 // output size is 128 bytes
|
||||
)
|
||||
switch success
|
||||
case 0 {
|
||||
@@ -144,12 +231,11 @@ contract MixinWrapperFunctions is
|
||||
mstore(add(fillResults, 96), 0)
|
||||
}
|
||||
case 1 {
|
||||
mstore(fillResults, mload(start))
|
||||
mstore(add(fillResults, 32), mload(add(start, 32)))
|
||||
mstore(add(fillResults, 64), mload(add(start, 64)))
|
||||
mstore(add(fillResults, 96), mload(add(start, 96)))
|
||||
mstore(fillResults, mload(headerAreaStart))
|
||||
mstore(add(fillResults, 32), mload(add(headerAreaStart, 32)))
|
||||
mstore(add(fillResults, 64), mload(add(headerAreaStart, 64)))
|
||||
mstore(add(fillResults, 96), mload(add(headerAreaStart, 96)))
|
||||
}
|
||||
|
||||
}
|
||||
return fillResults;
|
||||
}
|
||||
@@ -228,10 +314,10 @@ contract MixinWrapperFunctions is
|
||||
|
||||
// Token being sold by taker must be the same for each order
|
||||
require(orders[i].takerTokenAddress == orders[0].takerTokenAddress);
|
||||
|
||||
|
||||
// Calculate the remaining amount of takerToken to sell
|
||||
uint256 remainingTakerTokenFillAmount = safeSub(takerTokenFillAmount, totalFillResults.takerTokenFilledAmount);
|
||||
|
||||
|
||||
// Attempt to sell the remaining amount of takerToken
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
@@ -270,7 +356,7 @@ contract MixinWrapperFunctions is
|
||||
|
||||
// Calculate the remaining amount of takerToken to sell
|
||||
uint256 remainingTakerTokenFillAmount = safeSub(takerTokenFillAmount, totalFillResults.takerTokenFilledAmount);
|
||||
|
||||
|
||||
// Attempt to sell the remaining amount of takerToken
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
@@ -308,7 +394,7 @@ contract MixinWrapperFunctions is
|
||||
|
||||
// Calculate the remaining amount of makerToken to buy
|
||||
uint256 remainingMakerTokenFillAmount = safeSub(makerTokenFillAmount, totalFillResults.makerTokenFilledAmount);
|
||||
|
||||
|
||||
// Convert the remaining amount of makerToken to buy into remaining amount
|
||||
// of takerToken to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerTokenFillAmount = getPartialAmount(
|
||||
@@ -405,5 +491,5 @@ contract MixinWrapperFunctions is
|
||||
totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
|
||||
totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
import "/zeppelin/contracts/token/ERC721/ERC721Token.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract DummyERC721Token is
|
||||
Ownable,
|
||||
ERC721Token
|
||||
{
|
||||
function DummyERC721Token(
|
||||
string name,
|
||||
string symbol)
|
||||
public
|
||||
ERC721Token(name, symbol)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @dev Internal function to mint a new token
|
||||
* @dev Reverts if the given token ID already exists
|
||||
* @param to address the beneficiary that will own the minted token
|
||||
* @param tokenId uint256 ID of the token to be minted by the msg.sender
|
||||
*/
|
||||
function mint(address to, uint256 tokenId)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
super._mint(to, tokenId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./IAuthorizable.sol";
|
||||
import "../Ownable/Ownable.sol";
|
||||
|
||||
contract Authorizable is
|
||||
Ownable,
|
||||
IAuthorizable
|
||||
{
|
||||
|
||||
/// @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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
emit 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;
|
||||
}
|
||||
}
|
||||
emit LogAuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(address target, uint256 index)
|
||||
public
|
||||
{
|
||||
require(index < authorities.length);
|
||||
require(authorities[index] == target);
|
||||
delete authorized[target];
|
||||
authorities[index] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
emit LogAuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public constant functions
|
||||
*/
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
public
|
||||
constant
|
||||
returns (address[])
|
||||
{
|
||||
return authorities;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
/// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance.
|
||||
contract IAuthorizable {
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
public view
|
||||
returns (address[]);
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
public;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
public;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(address target, uint256 index)
|
||||
public;
|
||||
|
||||
event LogAuthorizedAddressAdded(
|
||||
address indexed target,
|
||||
address indexed caller);
|
||||
|
||||
event LogAuthorizedAddressRemoved(
|
||||
address indexed target,
|
||||
address indexed caller);
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
contract LibBytes {
|
||||
|
||||
/// @dev Reads an address from a position in a byte array.
|
||||
/// @param b Byte array containing an address.
|
||||
/// @param index Index in byte array of address.
|
||||
/// @return address from byte array.
|
||||
function readAddress(
|
||||
bytes b,
|
||||
uint256 index)
|
||||
public pure
|
||||
returns (address result)
|
||||
{
|
||||
require(b.length >= index + 20); // 20 is length of address
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
// 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
|
||||
index += 20;
|
||||
|
||||
// Read address from array memory
|
||||
assembly {
|
||||
// 1. Add index to to address of bytes array
|
||||
// 2. Load 32-byte word from memory
|
||||
// 3. Apply 20-byte mask to obtain address
|
||||
result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Writes an address into a specific position in a byte array.
|
||||
/// @param input Address to put into byte array.
|
||||
/// @param b Byte array to insert address into.
|
||||
/// @param index Index in byte array of address.
|
||||
function writeAddress(
|
||||
address input,
|
||||
bytes b,
|
||||
uint256 index)
|
||||
public pure
|
||||
{
|
||||
require(b.length >= index + 20); // 20 is length of address
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
// 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
|
||||
index += 20;
|
||||
|
||||
// Store address into array memory
|
||||
assembly {
|
||||
// The address occupies 20 bytes and mstore stores 32 bytes.
|
||||
// First fetch the 32-byte word where we'll be storing the address, then
|
||||
// apply a mask so we have only the bytes in the word that the address will not occupy.
|
||||
// Then combine these bytes with the address and store the 32 bytes back to memory with mstore.
|
||||
|
||||
// 1. Add index to address of bytes array
|
||||
// 2. Load 32-byte word from memory
|
||||
// 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address
|
||||
let neighbors := and(mload(add(b, index)), 0xffffffffffffffffffffffff0000000000000000000000000000000000000000)
|
||||
|
||||
// Store the neighbors and address into memory
|
||||
mstore(add(b, index), xor(input, neighbors))
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Reads a uint256 value from a position in a byte array.
|
||||
/// @param b Byte array containing a uint256 value.
|
||||
/// @param index Index in byte array of uint256 value.
|
||||
/// @return uint256 value from byte array.
|
||||
function readUint256(
|
||||
bytes b,
|
||||
uint256 index)
|
||||
public pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
require(b.length >= index + 32);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
index += 32;
|
||||
|
||||
// Read the uint256 from array memory
|
||||
assembly {
|
||||
result := mload(add(b, index))
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Writes a uint256 into a specific position in a byte array.
|
||||
/// @param input uint256 to put into byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
function writeUint256(
|
||||
uint256 input,
|
||||
bytes b,
|
||||
uint256 index)
|
||||
public pure
|
||||
{
|
||||
require(b.length >= index + 32);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
index += 32;
|
||||
|
||||
// Read the uint256 from array memory
|
||||
assembly {
|
||||
mstore(add(b, index), input)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
/*
|
||||
* 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 IOwnable {
|
||||
function transferOwnership(address newOwner)
|
||||
public;
|
||||
}
|
@@ -7,7 +7,9 @@ pragma solidity ^0.4.21;
|
||||
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
|
||||
*/
|
||||
|
||||
contract Ownable {
|
||||
import "../Ownable/IOwnable.sol";
|
||||
|
||||
contract Ownable is IOwnable {
|
||||
address public owner;
|
||||
|
||||
function Ownable()
|
||||
|
67
packages/contracts/src/utils/asset_proxy_utils.ts
Normal file
67
packages/contracts/src/utils/asset_proxy_utils.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { AssetProxyId } from './types';
|
||||
const ethersUtils = require('ethers-utils');
|
||||
|
||||
export function zeroPad(value: string, width: number): string {
|
||||
return '0'.repeat(width - value.length) + value;
|
||||
}
|
||||
|
||||
export function encodeAssetProxyId(assetProxyId: AssetProxyId, encoded_metadata: { value: string }) {
|
||||
encoded_metadata.value += zeroPad(new BigNumber(assetProxyId).toString(16), 2);
|
||||
}
|
||||
|
||||
export function encodeAddress(address: string, encoded_metadata: { value: string }) {
|
||||
encoded_metadata.value += zeroPad(address.replace('0x', ''), 40);
|
||||
}
|
||||
|
||||
export function encodeUint256(value: BigNumber, encoded_metadata: { value: string }) {
|
||||
encoded_metadata.value += zeroPad(value.toString(16), 64);
|
||||
}
|
||||
|
||||
export function encodeERC20ProxyMetadata_V1(tokenAddress: string) {
|
||||
// Encode metadata
|
||||
const encoded_metadata = { value: '0x' };
|
||||
encodeAssetProxyId(AssetProxyId.ERC20_V1, encoded_metadata);
|
||||
encodeAddress(tokenAddress, encoded_metadata);
|
||||
|
||||
// Verify encoding length - '0x' plus 21 bytes of encoded data
|
||||
if (encoded_metadata.value.length != 44) {
|
||||
throw Error('Bad encoding length. Expected 44, got ' + encoded_metadata.value.length);
|
||||
}
|
||||
|
||||
// Return encoded metadata
|
||||
return encoded_metadata.value;
|
||||
}
|
||||
|
||||
export function encodeERC20ProxyMetadata(tokenAddress: string) {
|
||||
// Encode metadata
|
||||
const encoded_metadata = { value: '0x' };
|
||||
encodeAssetProxyId(AssetProxyId.ERC20, encoded_metadata);
|
||||
encodeAddress(tokenAddress, encoded_metadata);
|
||||
|
||||
// Verify encoding length - '0x' plus 21 bytes of encoded data
|
||||
if (encoded_metadata.value.length != 44) {
|
||||
throw Error('Bad encoding length. Expected 44, got ' + encoded_metadata.value.length);
|
||||
}
|
||||
|
||||
// Return encoded metadata
|
||||
return encoded_metadata.value;
|
||||
}
|
||||
|
||||
export function encodeERC721ProxyMetadata(tokenAddress: string, tokenId: BigNumber) {
|
||||
// Encode metadata
|
||||
const encoded_metadata = { value: '0x' };
|
||||
encodeAssetProxyId(AssetProxyId.ERC721, encoded_metadata);
|
||||
encodeAddress(tokenAddress, encoded_metadata);
|
||||
encodeUint256(tokenId, encoded_metadata);
|
||||
|
||||
// Verify encoding length - '0x' plus 53 bytes of encoded data
|
||||
if (encoded_metadata.value.length != 108) {
|
||||
throw Error('Bad encoding length. Expected 108, got ' + encoded_metadata.value.length);
|
||||
}
|
||||
|
||||
// Return encoded metadata
|
||||
return encoded_metadata.value;
|
||||
}
|
@@ -26,5 +26,6 @@ export const constants = {
|
||||
MAX_TOKEN_TRANSFERFROM_GAS: 80000,
|
||||
MAX_TOKEN_APPROVE_GAS: 60000,
|
||||
DUMMY_TOKEN_ARGS: [DUMMY_TOKEN_NAME, DUMMY_TOKEN_SYMBOL, DUMMY_TOKEN_DECIMALS, DUMMY_TOKEN_TOTAL_SUPPLY],
|
||||
DUMMY_ERC721TOKEN_ARGS: [DUMMY_TOKEN_NAME, DUMMY_TOKEN_SYMBOL],
|
||||
TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)),
|
||||
};
|
||||
|
@@ -31,6 +31,8 @@ export const crypto = {
|
||||
argTypes.push('address');
|
||||
} else if (_.isString(arg)) {
|
||||
argTypes.push('string');
|
||||
} else if (arg instanceof Buffer) {
|
||||
argTypes.push('bytes');
|
||||
} else if (_.isBoolean(arg)) {
|
||||
argTypes.push('bool');
|
||||
} else {
|
||||
|
@@ -35,6 +35,8 @@ export const orderUtils = {
|
||||
takerFee: signedOrder.takerFee,
|
||||
expirationTimeSeconds: signedOrder.expirationTimeSeconds,
|
||||
salt: signedOrder.salt,
|
||||
makerAssetProxyData: signedOrder.makerAssetProxyData,
|
||||
takerAssetProxyData: signedOrder.takerAssetProxyData,
|
||||
};
|
||||
return orderStruct;
|
||||
},
|
||||
@@ -52,6 +54,8 @@ export const orderUtils = {
|
||||
'uint256 takerFee',
|
||||
'uint256 expirationTimeSeconds',
|
||||
'uint256 salt',
|
||||
'bytes makerAssetProxyData',
|
||||
'bytes takerAssetProxyData',
|
||||
]);
|
||||
const orderParamsHashBuff = crypto.solSHA3([
|
||||
order.exchangeAddress,
|
||||
@@ -66,6 +70,8 @@ export const orderUtils = {
|
||||
order.takerFee,
|
||||
order.expirationTimeSeconds,
|
||||
order.salt,
|
||||
ethUtil.toBuffer(order.makerAssetProxyData),
|
||||
ethUtil.toBuffer(order.takerAssetProxyData),
|
||||
]);
|
||||
const orderSchemaHashHex = `0x${orderSchemaHashBuff.toString('hex')}`;
|
||||
const orderParamsHashHex = `0x${orderParamsHashBuff.toString('hex')}`;
|
||||
|
@@ -37,6 +37,13 @@ export interface CancelOrdersBefore {
|
||||
salt: BigNumber;
|
||||
}
|
||||
|
||||
export enum AssetProxyId {
|
||||
INVALID,
|
||||
ERC20_V1,
|
||||
ERC20,
|
||||
ERC721,
|
||||
}
|
||||
|
||||
export interface DefaultOrderParams {
|
||||
exchangeAddress: string;
|
||||
makerAddress: string;
|
||||
@@ -45,8 +52,10 @@ export interface DefaultOrderParams {
|
||||
takerTokenAddress: string;
|
||||
makerTokenAmount: BigNumber;
|
||||
takerTokenAmount: BigNumber;
|
||||
makerFee: BigNumber;
|
||||
takerFee: BigNumber;
|
||||
makerFeeAmount: BigNumber;
|
||||
takerFeeAmount: BigNumber;
|
||||
makerAssetProxyData: string;
|
||||
takerAssetProxyData: string;
|
||||
}
|
||||
|
||||
export interface TransactionDataParams {
|
||||
@@ -100,6 +109,11 @@ export enum ContractName {
|
||||
AccountLevels = 'AccountLevels',
|
||||
EtherDelta = 'EtherDelta',
|
||||
Arbitrage = 'Arbitrage',
|
||||
AssetProxyDispatcher = 'AssetProxyDispatcher',
|
||||
ERC20TransferProxy = 'ERC20TransferProxy',
|
||||
ERC20TransferProxy_V1 = 'ERC20TransferProxy_v1',
|
||||
ERC721TransferProxy = 'ERC721TransferProxy',
|
||||
DummyERC721Token = 'DummyERC721Token',
|
||||
}
|
||||
|
||||
export interface Artifact {
|
||||
@@ -134,6 +148,8 @@ export interface OrderStruct {
|
||||
takerFee: BigNumber;
|
||||
expirationTimeSeconds: BigNumber;
|
||||
salt: BigNumber;
|
||||
makerAssetProxyData: string;
|
||||
takerAssetProxyData: string;
|
||||
}
|
||||
|
||||
export interface UnsignedOrder extends OrderStruct {
|
||||
|
Reference in New Issue
Block a user