Untested - Compliant Forwarder with Wyre "Yes Compliance" Token
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
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.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
||||
import "../../tokens/ERC721Token/IERC721Token.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract CompliantForwarder {
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
bytes4 constant internal EXCHANGE_FILL_ORDER_SELECTOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
|
||||
IExchange internal EXCHANGE;
|
||||
IERC721Token internal COMPLIANCE_TOKEN;
|
||||
|
||||
constructor(address exchange, address complianceToken)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(exchange);
|
||||
COMPLIANCE_TOKEN = IERC721Token(complianceToken);
|
||||
}
|
||||
|
||||
function fillOrder(
|
||||
uint256 salt,
|
||||
address signerAddress,
|
||||
bytes signedFillOrderTransaction,
|
||||
bytes signature
|
||||
)
|
||||
public
|
||||
{
|
||||
// Validate `signedFillOrderTransaction`
|
||||
bytes4 selector = signedFillOrderTransaction.readBytes4(0);
|
||||
if (selector != EXCHANGE_FILL_ORDER_SELECTOR) {
|
||||
revert("EXCHANGE_TRANSACTION_NOT_FILL_ORDER");
|
||||
}
|
||||
|
||||
// Extract maker address from fill order transaction
|
||||
// Below is the table of calldata offsets into a fillOrder transaction.
|
||||
/**
|
||||
### parameters
|
||||
0x00 ptr<order>
|
||||
0x20 takerAssetFillAmount
|
||||
0x40 ptr<signature>
|
||||
### order
|
||||
0x60 makerAddress
|
||||
0x80 takerAddress
|
||||
0xa0 feeRecipientAddress
|
||||
0xc0 senderAddress
|
||||
0xe0 makerAssetAmount
|
||||
0x100 takerAssetAmount
|
||||
0x120 makerFee
|
||||
0x140 takerFee
|
||||
0x160 expirationTimeSeconds
|
||||
0x180 salt
|
||||
0x1a0 ptr<makerAssetData>
|
||||
0x1c0 ptr<takerAssetData>
|
||||
0x1e0 makerAssetData
|
||||
* takerAssetData
|
||||
* signature
|
||||
------------------------------
|
||||
* Context-dependent offsets, unknown at compile time.
|
||||
*/
|
||||
// Add 0x4 to a given offset to account for the fillOrder selector prepended to `signedFillOrderTransaction`.
|
||||
// Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes.
|
||||
// Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70
|
||||
address makerAddress = signedFillOrderTransaction.readAddress(0x70);
|
||||
|
||||
// Verify maker/taker have been verified by the compliance token.
|
||||
if (COMPLIANCE_TOKEN.balanceOf(makerAddress) == 0) {
|
||||
revert("MAKER_UNVERIFIED");
|
||||
} else if (COMPLIANCE_TOKEN.balanceOf(signerAddress) == 0) {
|
||||
revert("TAKER_UNVERIFIED");
|
||||
}
|
||||
|
||||
// All entities are verified. Execute fillOrder.
|
||||
EXCHANGE.executeTransaction(
|
||||
salt,
|
||||
signerAddress,
|
||||
signedFillOrderTransaction,
|
||||
signature
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../ERC721Token/ERC721Token.sol";
|
||||
|
||||
/**
|
||||
* @notice an ERC721 "yes" compliance token supporting a collection of country-specific attributions which answer specific
|
||||
* compliance-related queries with YES. (attestations)
|
||||
*
|
||||
* primarily ERC721 is useful for the self-management of claiming addresses. a single token is more useful
|
||||
* than a non-ERC721 interface because of interop with other 721-supporting systems/ui; it allows users to
|
||||
* manage their financial stamp with flexibility using a well-established simple concept of non-fungible tokens.
|
||||
* this interface is for anyone needing to carry around and otherwise manage their proof of compliance.
|
||||
*
|
||||
* the financial systems these users authenticate against have a different set of API requirements. they need
|
||||
* more contextualization ability than a balance check to support distinctions of attestations, as well as geographic
|
||||
* distinction. these integrations are made simpler as the language of the query more closely match the language of compliance.
|
||||
*
|
||||
* this interface describes, beyond 721, these simple compliance-specific interfaces (and their management tools)
|
||||
*
|
||||
* notes:
|
||||
* - no address can be associated with more than one identity (though addresses may have more than token). issuance
|
||||
* in this circumstance will fail
|
||||
* - one person or business = one entity
|
||||
* - one entity may have many tokens across many addresses; they can mint and burn tokens tied to their identity at will
|
||||
* - two token types: control & non-control. both carry compliance proof
|
||||
* - control tokens let their holders mint and burn (within the same entity)
|
||||
* - non-control tokens are solely for compliance queries
|
||||
* - a lock on the entity is used instead of token revocation to remove the cash burden assumed by a customer to
|
||||
* redistribute a fleet of coins
|
||||
* - all country codes should be via ISO-3166-1
|
||||
*
|
||||
* any (non-view) methods not explicitly marked idempotent are not idempotent.
|
||||
*/
|
||||
contract YesComplianceTokenV1 is ERC721Token /*, ERC165 :should: */ {
|
||||
|
||||
uint256 public constant OWNER_ENTITY_ID = 1;
|
||||
|
||||
uint8 public constant YESMARK_OWNER = 128;
|
||||
uint8 public constant YESMARK_VALIDATOR = 129;
|
||||
|
||||
/*
|
||||
todo events: entity updated, destroyed, ????
|
||||
Finalized
|
||||
Attested
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @notice query api: returns true if the specified address has the given country/yes attestation. this
|
||||
* is the primary method partners will use to query the active qualifications of any particular
|
||||
* address.
|
||||
*/
|
||||
function isYes(uint256 _validatorEntityId, address _address, uint16 _countryCode, uint8 _yes) external view returns(bool) ;
|
||||
|
||||
/** @notice same as isYes except as an imperative */
|
||||
function requireYes(uint256 _validatorEntityId, address _address, uint16 _countryCode, uint8 _yes) external view ;
|
||||
|
||||
/**
|
||||
* @notice retrieve all YES marks for an address in a particular country
|
||||
* @param _validatorEntityId the validator ID to consider. or, use 0 for any of them
|
||||
* @param _address the validator ID to consider, or 0 for any of them
|
||||
* @param _countryCode the ISO-3166-1 country code
|
||||
* @return (non-duplicate) array of YES marks present
|
||||
*/
|
||||
function getYes(uint256 _validatorEntityId, address _address, uint16 _countryCode) external view returns(uint8[] /* memory */);
|
||||
|
||||
// function getCountries(uint256 _validatorEntityId, address _address) external view returns(uint16[] /* memory */);
|
||||
|
||||
/**
|
||||
* @notice create new tokens. fail if _to already
|
||||
* belongs to a different entity and caller is not validator
|
||||
* @param _control true if the new token is a control token (can mint, burn). aka NOT limited.
|
||||
* @param _entityId the entity to mint for, supply 0 to use the entity tied to the caller
|
||||
* @return the newly created token ID
|
||||
*/
|
||||
function mint(address _to, uint256 _entityId, bool _control) external returns (uint256);
|
||||
|
||||
/** @notice shortcut to mint() + setYes() in one call, for a single country */
|
||||
function mint(address _to, uint256 _entityId, bool _control, uint16 _countryCode, uint8[] _yes) external returns (uint256);
|
||||
|
||||
/** @notice destroys a specific token */
|
||||
function burn(uint256 _tokenId) external;
|
||||
|
||||
/** @notice destroys the entire entity and all tokens */
|
||||
function burnEntity(uint256 _entityId) external;
|
||||
|
||||
/**
|
||||
* @notice adds a specific attestations (yes) to an entity. idempotent: will return normally even if the mark
|
||||
* was already set by this validator
|
||||
*/
|
||||
function setYes(uint256 _entityId, uint16 _countryCode, uint8 _yes) external;
|
||||
|
||||
/**
|
||||
* @notice removes a attestation(s) from a specific validator for an entity. idempotent
|
||||
*/
|
||||
function clearYes(uint256 _entityId, uint16 _countryCode, uint8 _yes) external;
|
||||
|
||||
/** @notice removes all attestations in a given country for a particular entity. idempotent */
|
||||
function clearYes(uint256 _entityId, uint16 _countryCode) external;
|
||||
|
||||
/** @notice removes all attestations for a particular entity. idempotent */
|
||||
function clearYes(uint256 _entityId) external;
|
||||
|
||||
/** @notice assigns a lock to an entity, rendering all isYes queries false. idempotent */
|
||||
function setLocked(uint256 _entityId, bool _lock) external;
|
||||
|
||||
/** @notice checks whether or not a particular entity is locked */
|
||||
function isLocked(uint256 _entityId) external view returns(bool);
|
||||
|
||||
/** @notice returns true if the specified token has been finalized (cannot be moved) */
|
||||
function isFinalized(uint256 _tokenId) external view returns(bool);
|
||||
|
||||
/** @notice finalizes a token by ID preventing it from getting moved. idempotent */
|
||||
function finalize(uint256 _tokenId) external;
|
||||
|
||||
/** @return the entity ID associated with an address (or fail if there is not one) */
|
||||
function getEntityId(address _address) external view returns(uint256);
|
||||
|
||||
}
|
Reference in New Issue
Block a user