Interacting with the 0x smart contracts via Solidity
Short intro to 0x
I've been playing around with the 0x smart contracts recently as a means to getting better at Solidity. I decided to share what I've learnt as I had some trouble getting it to work at first, and most of the tutorials out there right now are interacting with the 0x contracts directly with Javascript. The first thing you need to understand to start working with 0x is how the ERC20 token works. From a very high level, each ERC20 token has its own contract, which holds the balance of people who own tokens. The function we will need from the token contract will be the allowance
function. 0x does all the trading for us, so what this function does it allows another smart contract to access our tokens. Once it has access, it can actually make the trades by pulling the tokens our of our smart contract using the TokenTransferProxy
contract.
The high level overview of how 0x works is that there are two main contracts. There is the Exchange
contract, which deals with verifying that the trade is correct and still available and there is the TokenTransferProxy
contract that deals with exchange the tokens between the two parties. This is the contract that needs the allowance
from your smart contract. You do not deploy your own 0x contracts, the contracts have already been deployed by the 0x team on the test and mainnet, which are free and open for anyone to use.
Coding your first trade
The only contract we will actually be interacting with is the Exchange
contract. The function we will want to call to make the trade is called fillOrder
and it takes all the information from the trade, and then passes the trade onto the TokenTransferProxy
contract if the trade is correct. Before calling that function we will first need to import the ERC20 standard Token
contract as an abstract contract so we have the interface to instantiate the tokens we want to allow our contract to trade with. We will then need to setup the Exchange abstract contract so we can call the fillOrder
function on it. We don't need anything but the address of the TokenTransferProxy
contract as we do not interact with it directly apart from giving it access to our token funds.
pragma solidity ^0.4.18;
import './Token.sol';
import './Exchange.sol';
contract Trader {
Exchange public zrxExchange;
address public zrxTokenTransferProxy;
function Trader (uint networkId) public {
zrxExchange = Exchange(0x90Fe2Af704B34E0224bF2299C838E04d4Dcf1364); //kovan exchange.sol
zrxTokenTransferProxy = 0x087Eed4Bc1ee3DE49BeFbd66C662B434B15d49d4;
}
function setAllowanceForProxyContract (address tokenContract, uint amount) public returns (bool success) {
Token tokenInstance = Token(tokenContract);
return tokenInstance.approve(zrxTokenTransferProxy, amount);
}
}
In this code we have setup the constructor and the variables for the Kovan testnet exchange and proxy addresses. We have also imported abstract contracts for the Exchange.sol
and the Token.sol
The next thing we need to do is to actually write the code for the trade, which is pretty simple. We just take all the arguments that is required for the trade and then call the fillOrder
function from the Exchange.sol
contract which does the rest for us.
function makeTrade(
address[5] orderAddresses,
uint[6] orderValues,
uint fillTakerTokenAmount,
bool shouldThrowOnInsufficientBalanceOrAllowance,
uint8 v,
bytes32 r,
bytes32 s
) public returns (uint tokenAmount) {
return zrxExchange.fillOrder(
orderAddresses,
orderValues,
fillTakerTokenAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
v,
r,
s
);
}
Test your trade
I was using Remix to test it as you can directly deploy your contract and then call functions it after in the same interface.
-
Create your order
Create your order with the 0x portal using your metamask account.
-
Deploy our contract
Set up an allowance by calling the
setAllowanceForProxyContract
function, which is already preloaded with theTokenProxyTransfer
address deployed on Kovan. -
Transfer tokens
Your smart contract needs the tokens you will be trading with your second account. You can use the 0x portal interface to send these dummy tokens to trade.
-
Make the trade
Call the
makeTrade
function using Remix and the correct arguments. Make sure if you haven't specified a taker you set your taker to0x000...
as the argument is for the signed trade itself and not for the taker who is actually taking the trade. In short that means, the taker's address (in this case our smart contract) does not actually have to be in the parameters unless it is actually specified in the trade JSON. Most of the time this won't be unless it is a private trade.
Conclusion
I've simplified the contract as much as possible for learning purposes, but you will most likely want to make the contract ownable using normal Solidity patterns, and you will want to create functions to actually withdraw your tokens such as this:
function withdrawToken(address tokenContract, uint amount) onlyOwner public returns(bool success){
Token tokenInstance = Token(tokenContract);
success = tokenInstance.transfer(owner, amount);
return success;
}