# Adapter
The airnode-adapter (opens new window) package has multiple responsibilities. It is used for building requests from an Oracle Integration Specification (OIS), executing them, parsing the responses, but also converting and encoding them for on chain use.
It is an internal dependency of Airnode, but can also be used standalone as an API.
# Installation
You can install @api3/airnode-adapter
by adding it to the package.json
file
in your project.
npm install --save @api3/airnode-adapter
# or by
yarn add @api3/airnode-adapter
2
3
You shouldn't need to use the adapter package directly. However, you might want to use its API to double check the conversion or encoding behavior for which you can install this package and verify your assumptions.
# Conversion
While the adapter package has many responsibilities, many of those can be treated as implementation details. On the other hand, there are a few important behaviors to be noted when converting the response values based on the target type and making the response transaction on chain.
Altogether, the response cycle consists of multiple steps
- A successful API call is made and Airnode receives a response value.
- The value to be converted is extracted from the response using the _path from the OIS object.
- This extracted value is converted to the target type. Conversions are
performed internally by the
castValue(value, type)
function. - The converted value is encoded to the native solidity type based on the
_type from the OIS object. Encoding
is performed internally by the
encodeValue(value, type)
function.
If any of the steps above fail, an error is thrown. This will fail the given API request and the error reason can be found in the logs.
The rest of this section covers the conversion logic for all of the supported types.
# int256
or uint256
Converting any of the values in the following example will result in an error:
const ERROR_VALUES = [
null,
undefined,
Infinity,
NaN,
'', // empty string
'randomstring',
[], // arrays of any kind
{}, // objects of any kind
];
2
3
4
5
6
7
8
9
10
There are a few special strings and boolean values that are convertible to
int256
or uint256
:
const SPECIAL_INT_VALUES = [false, 'false', true, 'true'];
const values = SPECIAL_INT_VALUES.map((v) => adapter.castValue(v, 'int256'));
console.log(values);
// [0, 0, 1, 1];
2
3
4
5
Number strings and numbers will attempt to be converted to BigNumbers (opens new window). The value will also be multiplied by the value of the _times parameter if it is present.
const VALID_INT_VALUES = ['123.456', 7777];
const values = VALID_INT_VALUES.map((v) => adapter.castValue(v, 'uint256'));
console.log(values);
// [new BigNumber(123.456), new BigNumber(7777)];
2
3
4
5
Conversion for int256
and uint256
is the same - this means that -123
can
be converted to uint256
. However, an error will be thrown while encoding.
Flooring
Beware that any floating point number will be floored. This is necessary,
because floating point numbers are not valid in solidity. To mitigate precision
loss, you can use the _times
parameter that is sufficiently large.
For example, if the API response is a USD currency, you might want to use
_times: "100"
to convert the value to cents.
# bool
Converting values in the example are all considered false
.
const FALSE_BOOLEAN_VALUES = [0, '0', false, 'false', undefined, null];
const values = FALSE_BOOLEAN_VALUES.map((v) => {
return adapter.castValue(v, 'bool');
});
console.log(values);
// [false, false, false, false, false, false];
2
3
4
5
6
7
8
All other values are converted to true
.
# bytes32
There is no conversion for bytes32
- the value is expected to be a valid hex
string representing the encoded 32 bytes value. This means that the encoding
must be implemented on the API side. If you want to delegate the encoding to
Airnode, see the documentation for
string32
.
For example, let's say the API wants to encode the following string
simple string
with length 13. Its encoding is
0x73696d706c6520737472696e6700000000000000000000000000000000000000
.
This is the value that should be sent as a response to Airnode request, together
with the 0x
prefix.
You can use ethers (opens new window) to encode these on the API side
const value = 'simple string';
const encoded = ethers.utils.formatBytes32String(value);
console.log(encoded); // 0x73696d706c6520737472696e6700000000000000000000000000000000000000
2
3
# address
There is no conversion for address
- the value is expected to be a string
representing a valid address. Valid examples are:
0x0765baA22F6D4A53847D63B056DC79400b9A592a
- EIP-55 mixed case checksum (opens new window) of an address.0x0765baa22f6d4a53847d63b056dc79400b9a592a
- all lowercase address.
# bytes
There is no conversion for bytes
- the value is expected to be a valid hex
string representing the encoded value. This means that the encoding to bytes
must be implemented on the API side. If you want to send a string, see the
documentation for string
.
For example, let's say the API wants to encode the following string
this is an example string that is a bit longer
. Its encoding is
0x7468697320697320616e206578616d706c6520737472696e672074686174206973206120626974206c6f6e676572
.
This is the value that should be sent as a response to Airnode request, together
with the 0x
prefix.
You can use ethers (opens new window) to encode these on the API side
const value = 'this is an example string that is a bit longer';
const encodedValue = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(value));
console.log(encodedValue); // 0x7468697320697320616e206578616d706c6520737472696e672074686174206973206120626974206c6f6e676572
2
3
# string
You can pass any value to convert it to string - with the exception of arrays
and objects, which will throw an error. All other values will be converted to
string
and before encoded on chain using the string
type.
const values = [
-1,
0,
777.89,
null,
'simple string',
'this is an example string that is a bit longer',
];
// ["-1", "0", "777.89", "null", "simple string", "this is an example string that is a bit longer"]
const mappedValues = values.map((v) => {
return adapter.castValue(v, 'string');
});
2
3
4
5
6
7
8
9
10
11
12
13
# string32
You can pass any value to convert it to string - with the exception of arrays and objects, which will throw an error.
However, there is one exception, if the stringified value contains more than 31 characters it will be trimmed down to only the first 31 characters during conversion.
For example, if the API response is the following string
this is an example string that is a bit longer
with length 46. It will be
first trimmed to 31 characters, string this is an example string that
and
afterwards converted to
0x7468697320697320616e206578616d706c6520737472696e6720746861742000
.
You can use ethers (opens new window) to decode the values off chain using the following snippet
const encoded =
'0x7468697320697320616e206578616d706c6520737472696e6720746861742000';
const decoded = ethers.utils.parseBytes32String(encoded);
console.log(decoded); // "this is an example string that "
2
3
4
# Arrays
Conversion of arrays depends on the primitive type. All values of the array (or nested array) will be converted according to the rules of the primitive type.
For example: