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:
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.