You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Rename Durin to CCIP read and make edits for clarity
* Rewrite to use continuation-passing style
* Tweaks based on Makoto's feedback
* Add process diagram
* Update to use a list of URLs, and support multiple lookups
* Fix spelling error
* Rewrite to use GET
* Change response type to JSON
@@ -125,69 +125,64 @@ function balanceOf(address addr) public view returns(uint balance) {
125
125
Note that in this example the contract is returning `addr` in both `callData` and `extraData`, because it is required both by the gateway (in order to look up the data) and the callback function (in order to verify it). The contract cannot simply pass it to the gateway and rely on it being returned in the response, as this would give the gateway an opportunity to respond with an answer to a different query than the one that was initially issued.
126
126
127
127
### Gateway Interface
128
-
The URLs returned by a contract may be of any schema, but this specification only defines how clients should handle HTTPS URLs. Compliant gateways MUST accept POST requests with a Content-Type of `application/json`, matching the following schema:
128
+
The URLs returned by a contract may be of any schema, but this specification only defines how clients should handle HTTPS URLs.
129
+
130
+
Given a URL returned in an `OffchainLookup`, the URL to query is composed by concatenating the lower-case 0x-prefixed hexadecimal representations of the `sender` and `callData`, separated by forward slashes ('/').
131
+
132
+
For example, if a contract returns the following data in an `OffchainLookup`:
The request URL to query is `https://example.com/gateway/0xaabbccddeeaabbccddeeaabbccddeeaabbccddee/0x00112233`.
141
+
142
+
Compliant gateways MUST respond with a Content-Type of `application/json`, with the body adhering to the following JSON schema:
129
143
```
130
144
{
131
-
id: string,
132
-
data: {
133
-
to: string,
134
-
data: string
145
+
"type": "object",
146
+
"properties": {
147
+
"data": {
148
+
"type": "string",
149
+
"description: "0x-prefixed hex string containing the result data."
150
+
}
135
151
}
136
152
}
137
153
```
138
154
139
-
Where:
140
-
-`id` - string - A request ID, which will be returned in the response.
141
-
-`to` - string - The Ethereum address of the contract that reverted with `OffchainLookup`, in '0x' prefixed hex format.
142
-
-`data` - string - The value of the `callData` argument from the `OffchainLookup` error, in '0x' prefixed hex format.
143
-
144
-
Compliant gateways MUST respond with a Content-Type of `application/json`, matching the following schema:
145
-
155
+
Unsuccessful requests MUST return the appropriate HTTP status code - for example, 404 if the `sender` address is not supported by this gateway, 400 if the `callData` is in an invalid format, 500 if the server encountered an internal error, and so forth. The Content-Type of a 4xx or 5xx response MUST also be `application/json`, with the body adhering to the following JSON schema:
146
156
```
147
157
{
148
-
jobRunID: string,
149
-
statusCode: integer,
150
-
data: {
151
-
result: string
152
-
},
153
-
error: {
154
-
name: string,
155
-
message: string
158
+
"type": "object",
159
+
"properties": {
160
+
"message": {
161
+
"type": "string",
162
+
"description: "A human-readable error message."
163
+
}
156
164
}
157
165
}
158
166
```
159
167
160
-
Where:
161
-
-`jobRunID` - string - The request ID from the original request.
162
-
-`statusCode` - number - A status code, matching the semantics in [RFC 2616 §6.1.1](https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1). 200 indicates a successful response.
163
-
-`data` - object - Required if the status code is between 200 and 299, forbidden otherwise. Contains the response data.
164
-
-`result` - string - The response data from the call to the gateway, in '0x' prefixed hex format.
165
-
-`error` - object - Required if the status code is between 400 and 599, forbidden otherwise. Contains the error information.
166
-
-`name` - string - A short human-readable message giving the nature of the error.
167
-
-`message` - string - A human-readable message describing the error.
168
-
169
168
#### Example
170
169
```
171
170
// Request
172
-
curl -X POST --data '{"id": "1","data":{to:"0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8", data: "0xd5fa2b00...", }}"}'
@@ -200,33 +195,24 @@ A client that supports CCIP read MUST make contract calls using the following pr
200
195
3. If the function returns an error other than `OffchainLookup`, return it to the caller in the usual fashion.
201
196
4. Otherwise, decode the `sender`, `urls`, `callData`, `callbackFunction` and `extraData` arguments from the `OffchainLookup` error.
202
197
5. If the `sender` field does not match the address of the contract that was called, return an error to the caller and stop.
203
-
6. Make an HTTP POST request to one of the URLs specified in `urls`. The client may choose which URLs to try in which order, but SHOULD prioritise URLs earlier in the list over those later in the list. POST requests are formatted as specified in [Gateway Interface](#gateway-interface).
204
-
7. If the response code from step (5) is in the range 400-499, return an error to the caller and stop.
205
-
8. If the response code from step (5) is in the range 500-599, go back to step (5) and pick a different URL, or stop if there are no further URLs to try.
206
-
9. Otherwise, replace `data` with an ABI-encoded call to the contract function specified by the 4-byte selector `callbackFunction`, supplying `data.result` from step (6) and `extraData` from step (4), and return to step (1).
198
+
6. Construct a request URL by concatenating one of the URLs specified in `urls`, the lowercase 0x-prefixed hexadecimal representation of `sender`, and the lowercase 0x-prefixed hexadecimal representation of `callData`, separated by forward slashes ('/'). The client may choose which URLs to try in which order, but SHOULD prioritise URLs earlier in the list over those later in the list.
199
+
7. Make an HTTP GET request to the request URL.
200
+
8. If the response code from step (5) is in the range 400-499, return an error to the caller and stop.
201
+
9. If the response code from step (5) is in the range 500-599, go back to step (5) and pick a different URL, or stop if there are no further URLs to try.
202
+
10. Otherwise, replace `data` with an ABI-encoded call to the contract function specified by the 4-byte selector `callbackFunction`, supplying the data returned from step (7) and `extraData` from step (4), and return to step (1).
203
+
204
+
Clients MUST handle HTTP status codes appropriately, employing best practices for error reporting and retries.
207
205
208
206
This protocol can result in multiple lookups being requested by the same contract. Clients MUST implement a limit on the number of lookups they permit for a single contract call, and this limit SHOULD be at least 4.
209
207
210
208
The lookup protocol for a client is described with the following pseudocode:
data =abi.encodeWithSelector(callbackFunction, result.result, extraData);
236
+
constresult=httpcall(urls, to, callData);
237
+
data =abi.encodeWithSelector(callbackFunction, result, extraData);
252
238
}
253
239
}
254
240
thrownewError("Too many CCIP read redirects");
@@ -284,8 +270,8 @@ Using a revert, and conveying the required information in the revert data, allow
284
270
### Existence of `extraData` argument
285
271
`extraData` allows the original contract function to pass information to a subsequent invocation. Since contracts are not persistent, without this data a contract has no state from the previous invocation. Aside from allowing arbitrary contextual information to be propagated between the two calls, this also allows the contract to verify that the query the gateway answered is in fact the one the contract originally requested.
286
272
287
-
### Use of JSON for the gateway interface
288
-
JSON is widely used as a low-overhead way of making RPC calls over HTTP. We have used it here in order to minimise cognitive and tooling overhead for developers.
273
+
### Use of GET requests for the gateway interface
274
+
Using a GET request, with query data encoded in the URL, minimises complexity and enables entirely static implementations of gateways - in some applications a gateway can simply be an HTTP server or IPFS instance with a static set of responses in text files.
289
275
290
276
## Backwards Compatibility
291
277
Existing contracts that do not wish to use this specification are unaffected. Clients can add support for CCIP read to all contract calls without introducing any new overhead or incompatibilities.
0 commit comments