By default, Relay quotes are paid for with an unvalidated transfer. This keeps gas cost to an absolute minimum. However, if you want to do your own onchain validation, this is possible. We offer an Attestation API where the Solver will attest to any subset of the order parameters, which you can check onchain. For example, you could validate that:
  • Correct amount was sent
  • Request has not already been paid for
  • Request ID is valid
  • Request has not expired
  • Recipient is on a known whitelist

Guide

First of all, you can make a regular request via the /quote API
curl -X POST https://api.relay.link/quote -H 'Content-Type: application/json' -d 
'{
    "user":"0xf3d63166F0Ca56C3c1A3508FcE03Ff0Cf3Fb691e",
    "originChainId":1,"destinationChainId":7777777,"originCurrency":"0x0000000000000000000000000000000000000000",
    "destinationCurrency":"0x0000000000000000000000000000000000000000",
    "recipient":"0xf3d63166F0Ca56C3c1A3508FcE03Ff0Cf3Fb691e",
    "tradeType":"EXACT_INPUT",
    "amount":"700000000000000000",
    "referrer":"relay.link/swap","useExternalLiquidity":false
}' | jq
In the steps data we return you’ll see the corresponding request id associated to this quote you can take the request id and pass it to the /requests/:requestId/signature API
curl -X GET https://api.relay.link/requests/0x910113af21b5771f35712ab2680b578e5551a2e358916d9c540aa4f613418e2a/signature
The signature API will get you a response as below:
{
  "requestData": {
    "originChainId": 1,
    "originUser": "0xf3d63166F0Ca56C3c1A3508FcE03Ff0Cf3Fb691e",
    "originCurrency": "0x0000000000000000000000000000000000000000",
    "originAmount": "700000000000000000",
    "destinationChainId": 7777777,
    "destinationUser": "0xf3d63166F0Ca56C3c1A3508FcE03Ff0Cf3Fb691e"
  },
  "signature": "0x4c320680bbb7f4d46892cd93eddf04884d997c8a3dbd8af20ca502e6bf5323a07bb467f97e290dfd53350683ea494e4fcb02a445ac129d1741a81c12eed066a11b"
}
You can use the data to do various validations onchain. The signature is always generated by our EVM solver wallet (0xf70da97812cb96acdf810712aa562db8dfa3dbef), which has the same address across all chains we support - below is the signature generation code which you can replicate in Solidity to check that indeed the signed request data is coming from our solver:
export const signRequestData = async (requestId: string, requestData: RequestData) => {
  const packedRequestData = defaultAbiCoder.encode(
    ["bytes32", "uint256", "bytes32", "bytes32", "uint256", "uint256", "bytes32"],
    [
      requestId,
      requestData.originChainId,
      requestData.originUser,
      requestData.originCurrency,
      requestData.originAmount,
      requestData.destinationChainId,
      requestData.destinationUser,
    ]
  );

  return getSolver().signMessage(arrayify(keccak256(packedRequestData)));
};