@api3/airnode-abi
Advanced tools
Comparing version
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -43,24 +7,23 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
exports.decode = void 0; | ||
var ethers_1 = require("ethers"); | ||
var chunk_1 = __importDefault(require("lodash/chunk")); | ||
var constants_1 = require("./constants"); | ||
const ethers_1 = require("ethers"); | ||
const chunk_1 = __importDefault(require("lodash/chunk")); | ||
const constants_1 = require("./constants"); | ||
// Certain types need to be parsed after ABI decoding happens | ||
var VALUE_TRANSFORMATIONS = { | ||
const VALUE_TRANSFORMATIONS = { | ||
string32: ethers_1.ethers.utils.parseBytes32String, | ||
int256: function (value) { return value.toString(); }, | ||
uint256: function (value) { return value.toString(); }, | ||
int256: (value) => value.toString(), | ||
uint256: (value) => value.toString(), | ||
}; | ||
function buildDecodedMap(types, nameValuePairs) { | ||
return nameValuePairs.reduce(function (acc, pair, index) { | ||
var _a, _b; | ||
var _c = __read(pair, 2), encodedName = _c[0], encodedValue = _c[1]; | ||
var name = ethers_1.ethers.utils.parseBytes32String(encodedName); | ||
var type = types[index]; | ||
var transform = VALUE_TRANSFORMATIONS[type]; | ||
return nameValuePairs.reduce((acc, pair, index) => { | ||
const [encodedName, encodedValue] = pair; | ||
const name = ethers_1.ethers.utils.parseBytes32String(encodedName); | ||
const type = types[index]; | ||
const transform = VALUE_TRANSFORMATIONS[type]; | ||
// If the type does not need to be transformed, return it as is | ||
if (!transform) { | ||
return __assign(__assign({}, acc), (_a = {}, _a[name] = encodedValue, _a)); | ||
return Object.assign(Object.assign({}, acc), { [name]: encodedValue }); | ||
} | ||
var parsedValue = transform(encodedValue); | ||
return __assign(__assign({}, acc), (_b = {}, _b[name] = parsedValue, _b)); | ||
const parsedValue = transform(encodedValue); | ||
return Object.assign(Object.assign({}, acc), { [name]: parsedValue }); | ||
}, {}); | ||
@@ -75,19 +38,19 @@ } | ||
// const header = encodedData.substring(0, 66); | ||
var header = ethers_1.ethers.utils.hexlify(ethers_1.ethers.utils.arrayify(encodedData).slice(0, 32)); | ||
var parsedHeader = ethers_1.ethers.utils.parseBytes32String(header); | ||
const header = ethers_1.ethers.utils.hexlify(ethers_1.ethers.utils.arrayify(encodedData).slice(0, 32)); | ||
const parsedHeader = ethers_1.ethers.utils.parseBytes32String(header); | ||
// Get and validate the first character of the header | ||
var encodedEncodingVersion = parsedHeader.substring(0, 1); | ||
const encodedEncodingVersion = parsedHeader.substring(0, 1); | ||
if (encodedEncodingVersion !== '1') { | ||
throw new Error("Unknown ABI schema version: ".concat(encodedEncodingVersion)); | ||
throw new Error(`Unknown ABI schema version: ${encodedEncodingVersion}`); | ||
} | ||
// The version is specified by the first byte and the parameters are specified by the rest | ||
var encodedParameterTypes = parsedHeader.substring(1); | ||
const encodedParameterTypes = parsedHeader.substring(1); | ||
// Replace encoded types with full type names | ||
var fullParameterTypes = Array.from(encodedParameterTypes).map(function (type) { return constants_1.PARAMETER_SHORT_TYPES[type]; }); | ||
const fullParameterTypes = Array.from(encodedParameterTypes).map((type) => constants_1.PARAMETER_SHORT_TYPES[type]); | ||
// The first `bytes32` is the type encoding | ||
var initialDecodedTypes = ['bytes32']; | ||
var decodingTypes = fullParameterTypes.reduce(function (acc, type) { | ||
const initialDecodedTypes = ['bytes32']; | ||
const decodingTypes = fullParameterTypes.reduce((acc, type) => { | ||
var _a; | ||
// Each parameter is expected to have a `bytes32` name | ||
return __spreadArray(__spreadArray([], __read(acc), false), ['bytes32', (_a = constants_1.TYPE_TRANSFORMATIONS[type]) !== null && _a !== void 0 ? _a : type], false); | ||
return [...acc, 'bytes32', (_a = constants_1.TYPE_TRANSFORMATIONS[type]) !== null && _a !== void 0 ? _a : type]; | ||
}, initialDecodedTypes); | ||
@@ -97,10 +60,10 @@ // It's important to leave the `encodedData` intact here and not try to trim off the first | ||
// exactly what you got from the contract, including the header. | ||
var decodedData = ethers_1.ethers.utils.defaultAbiCoder.decode(decodingTypes, encodedData); | ||
const decodedData = ethers_1.ethers.utils.defaultAbiCoder.decode(decodingTypes, encodedData); | ||
// Checks if the original encoded data matches the re-encoded data | ||
var reEncodedData = ethers_1.ethers.utils.defaultAbiCoder.encode(decodingTypes, decodedData); | ||
const reEncodedData = ethers_1.ethers.utils.defaultAbiCoder.encode(decodingTypes, decodedData); | ||
if (reEncodedData !== encodedData) { | ||
throw new Error('Re-encoding mismatch'); | ||
} | ||
var _a = __read(decodedData), _version = _a[0], decodedParameters = _a.slice(1); | ||
var nameValuePairs = (0, chunk_1.default)(decodedParameters, 2); | ||
const [_version, ...decodedParameters] = decodedData; | ||
const nameValuePairs = (0, chunk_1.default)(decodedParameters, 2); | ||
return buildDecodedMap(fullParameterTypes, nameValuePairs); | ||
@@ -107,0 +70,0 @@ } |
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -32,26 +7,26 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
exports.encode = void 0; | ||
var ethers_1 = require("ethers"); | ||
var flatMap_1 = __importDefault(require("lodash/flatMap")); | ||
var constants_1 = require("./constants"); | ||
var VERSION = '1'; | ||
const ethers_1 = require("ethers"); | ||
const flatMap_1 = __importDefault(require("lodash/flatMap")); | ||
const constants_1 = require("./constants"); | ||
const VERSION = '1'; | ||
// Certain types need to be encoded/transformed before ABI encoding happens | ||
var VALUE_TRANSFORMATIONS = { | ||
const VALUE_TRANSFORMATIONS = { | ||
string32: ethers_1.ethers.utils.formatBytes32String, | ||
}; | ||
function buildSchemaHeader(types) { | ||
var allShortTypes = Object.keys(constants_1.PARAMETER_SHORT_TYPES); | ||
const allShortTypes = Object.keys(constants_1.PARAMETER_SHORT_TYPES); | ||
// Shorten all selected types with the corresponding "short" type | ||
// i.e. 'address' types get set as simply 'a' and 'bytes32' becomes | ||
// simply 'b' etc | ||
var selectedShortTypes = types.reduce(function (acc, type) { | ||
var shortType = allShortTypes.find(function (st) { return constants_1.PARAMETER_SHORT_TYPES[st] === type; }); | ||
return __spreadArray(__spreadArray([], __read(acc), false), [shortType], false); | ||
const selectedShortTypes = types.reduce((acc, type) => { | ||
const shortType = allShortTypes.find((st) => constants_1.PARAMETER_SHORT_TYPES[st] === type); | ||
return [...acc, shortType]; | ||
}, []); | ||
return "".concat(VERSION).concat(selectedShortTypes.join('')); | ||
return `${VERSION}${selectedShortTypes.join('')}`; | ||
} | ||
function buildNameValuePairs(parameters) { | ||
return (0, flatMap_1.default)(parameters, function (parameter) { | ||
var name = parameter.name, value = parameter.value, type = parameter.type; | ||
var transform = VALUE_TRANSFORMATIONS[type]; | ||
var encodedName = ethers_1.ethers.utils.formatBytes32String(name); | ||
return (0, flatMap_1.default)(parameters, (parameter) => { | ||
const { name, value, type } = parameter; | ||
const transform = VALUE_TRANSFORMATIONS[type]; | ||
const encodedName = ethers_1.ethers.utils.formatBytes32String(name); | ||
// If the type does not need to be transformed, return it as is | ||
@@ -61,3 +36,3 @@ if (!transform) { | ||
} | ||
var encodedValue = transform(value); | ||
const encodedValue = transform(value); | ||
return [encodedName, encodedValue]; | ||
@@ -67,19 +42,19 @@ }); | ||
function encode(parameters) { | ||
var types = parameters.map(function (parameter) { return parameter.type; }); | ||
const types = parameters.map((parameter) => parameter.type); | ||
// Each parameter name is represented by a `bytes32` string. The value | ||
// types are what the user provides | ||
var nameTypePairs = (0, flatMap_1.default)(types, function (type) { | ||
var transformedType = constants_1.TYPE_TRANSFORMATIONS[type]; | ||
const nameTypePairs = (0, flatMap_1.default)(types, (type) => { | ||
const transformedType = constants_1.TYPE_TRANSFORMATIONS[type]; | ||
return ['bytes32', transformedType !== null && transformedType !== void 0 ? transformedType : type]; | ||
}); | ||
// The first type is always a bytes32 as it represents the schema header | ||
var allTypes = __spreadArray(['bytes32'], __read(nameTypePairs), false); | ||
const allTypes = ['bytes32', ...nameTypePairs]; | ||
// Build the schema which includes the version and the abbreviated list of parameters | ||
var schemaHeader = buildSchemaHeader(types); | ||
var encodedHeader = ethers_1.ethers.utils.formatBytes32String(schemaHeader); | ||
const schemaHeader = buildSchemaHeader(types); | ||
const encodedHeader = ethers_1.ethers.utils.formatBytes32String(schemaHeader); | ||
// Map and encode each name/value pair where necessary | ||
var flatNameValues = buildNameValuePairs(parameters); | ||
const flatNameValues = buildNameValuePairs(parameters); | ||
// The schema header is always the first value to be encoded | ||
var allValues = __spreadArray([encodedHeader], __read(flatNameValues), false); | ||
var encoder = new ethers_1.ethers.utils.AbiCoder(); | ||
const allValues = [encodedHeader, ...flatNameValues]; | ||
const encoder = new ethers_1.ethers.utils.AbiCoder(); | ||
return encoder.encode(allTypes, allValues); | ||
@@ -86,0 +61,0 @@ } |
{ | ||
"name": "@api3/airnode-abi", | ||
"license": "MIT", | ||
"version": "0.7.5", | ||
"version": "0.8.0", | ||
"private": false, | ||
@@ -13,3 +13,3 @@ "main": "dist/index", | ||
"build": "yarn run clean && yarn run compile", | ||
"clean": "rimraf -rf *.tsbuildinfo ./dist *.tgz", | ||
"clean": "rimraf -rf *.tsbuildinfo ./dist ./build *.tgz", | ||
"compile": "tsc --build tsconfig.json", | ||
@@ -21,11 +21,11 @@ "pack": "yarn pack", | ||
"dependencies": { | ||
"ethers": "^5.4.5", | ||
"ethers": "^5.7.0", | ||
"lodash": "^4.17.21" | ||
}, | ||
"devDependencies": { | ||
"@types/lodash": "^4.14.169", | ||
"jest": "^26.6.3", | ||
"@types/lodash": "^4.14.184", | ||
"jest": "^29.0.2", | ||
"rimraf": "^3.0.2", | ||
"typescript": "^4.2.4" | ||
"typescript": "^4.8.2" | ||
} | ||
} |
# `@api3/airnode-abi` | ||
> Encoding and decoding utilities for Airnode according to the | ||
> [Airnode ABI specifications](https://docs.api3.org/airnode/latest/reference/specifications/airnode-abi-specifications.html) | ||
## Documentation | ||
The Airnode-ABI package provides a unique way to encode and decode parameters. Parameters are provided with encoding | ||
@@ -4,0 +9,0 @@ types, names and values. The types are shortened and grouped with a version as the "header". The name/value pairs are |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
16
45.45%19627
-74.06%23
-4.17%212
-22.63%Updated