Last month we discussed some of the regulatory obligations that pertain to running a platform like OpenRelay. One of the commitments we made was an updated terms of use, along with technical measures to require that users have read and agreed to them to use our service.

Today we are deploying the first of two phases of this commitment.

Phase One

As of today, our terms of use is available, and we have tooling to enable users to sign the terms of use with their Ethereum accounts. During phase one we will not require users to sign the terms of use to submit orders, but will give the opportunity to sign it in advance of enforcment.

If you use OpenRelay in your dApp, you can use our Widget library to help your users sign our terms of use. The widget can easily be embedded into any HTML page, and makes signing the terms of use quick and easy.

If you are viewing the blog through a Web3 enable browser, you can sign the terms of use right here:

You have accepted the terms of use! You need a web3 client to sign the OpenRelay Terms of Use If you interact with OpenRelay through Massive, we have a branch which adds a subcommand for signing the terms of use. We hope to make an official release of Massive for 0x v2 soon, but for now the code is available on Github.

Phase Two

Next Thursday, December 20th, we will require that any new orders submitted to OpenRelay come from a maker that has a Terms of Use signature on file with us. This is a short window for users to sign the Terms of Use before it becomes a requirement, but we felt a transition period that would enable users to sign the Terms of Use before enforcement is in effect would help things go as smoothly as possible.

Open Source Implications

Obviously OpenRelay is an Open Source project. The terms of use we are requiring apply to OpenRelay.xyz, our hosted implementation of OpenRelay. Anyone running their own instance of OpenRelay is welcome to use their own terms, or the ingest service can easily be configured not to require acceptance of a terms of use.

Technical Details

Developers can check whether a given address has signed the terms of use by making a GET request to https://api.openrelay.xyz/v2/_tos/$ADDRESS. It will return a 204 status code if the user has signed the terms of use, and a 404 status code if they have not. Neither result will have content.

Users can retrieve the terms of use with a GET request to https://api.openrelay.xyz/v2/_tos. This will provide a JSON document of the form:

{
  "text": "$TERMS_TEXT",
  "id": $TERMS_IDENTIFIER,
  "mask": "$A_BIG_NUMBER",
  "maskId": $MASK_IDENTIFIER
}

The text field will contain the terms of use. The mask will be a large integer. To sign the terms of use, the user must provide a nonce value where:

hash = keccak256(
  $TERMS_TEXT
  $TIMESTAMP
  $NONCE_AS_HEX
)

matches the hash mask such that:

(int(hash) & mask) == mask

That is, any bits that are 1 in the mask must also be 1 in the hash. This mask allows us to increase the computational requirements of signing up a new account. At present, the mask will have 3x 1 bits, so on average it will take 8 attempts to find a valid nonce. This is high enough to ensure that implementers account for the nonce, but low enough to avoid impacting dApp performance. In the event of a denial of service attack, we have the option to increase the value to force an attacker signing up numerous accounts to spend vastly more computing time to create accounts than it takes us to process them.

The value of $TERMS_TEXT must match the value from the JSON response, and $TIMESTAMP is the number of second since the epoch, and must be in the 5 minutes prior to submitting the signature to the API.

Next, the string:

$TERMS_TEXT
$TIMESTAMP
$NONCE_AS_HEX

Must be signed by the maker’s keys using the ETH Sign protocol from the 0x v2 specification. Note that the signed value is not the hash of the above string, but the string itself — this ensures that Web3 client will show the user readable terms.

Once the nonce and signature have been computed, make a POST request to https://api.openrelay.xyz/v2/_tos with the body:

{
  "terms_id": $TERMS_IDENTIFIER,
  "mask_id": $MASK_IDENTIFIER,
  "sig": "$CALCULATED_SIGNATURE_AS_HEX",
  "address": "$ETHEREUM_ADDRESS_MATCHING_SIGNATURE",
  "timestamp": "$TIMESTAMP",
  "nonce": "$NONCE_AS_HEX"
}

If the nonce and timstamp combined with the terms produce a hash that matches the mask, the timestamp is less than five minutes old, and signature is valid, the API will return 202 and the maker will be able to submit orders immediately.

Implementations of this protocol can be seen in the widgets library and in Massive.