Skip to content

Instantly share code, notes, and snippets.

@kran
Last active December 16, 2024 06:21
Show Gist options
  • Save kran/15d4c51ee4a4063af9a718e6c3a78931 to your computer and use it in GitHub Desktop.
Save kran/15d4c51ee4a4063af9a718e6c3a78931 to your computer and use it in GitHub Desktop.
ethers.nashorn.js
/**
* <dependency>
* <groupId>org.bouncycastle</groupId>
* <artifactId>bcprov-jdk18on</artifactId>
* <version>1.79</version>
* </dependency>
*/
(function() {
const version = "6.13.1";
const WordSize = 32;
const Padding = new Uint8Array(WordSize);
const maxValue = 0x1fffffffffffff;
const BigInteger = Java.type('java.math.BigInteger');
const MessageDigest = Java.type('java.security.MessageDigest');
const ByteArray = Java.type('byte[]');
const Security = Java.type('java.security.Security');
const BouncyCastleProvider = Java.type('org.bouncycastle.jce.provider.BouncyCastleProvider');
Security.addProvider(new BouncyCastleProvider());
const HttpClient = Java.type("java.net.http.HttpClient");
const HttpRequest = Java.type("java.net.http.HttpRequest");
const HttpResponse = Java.type("java.net.http.HttpResponse");
const URI = Java.type("java.net.URI");
const BodyPublishers = Java.type("java.net.http.HttpRequest.BodyPublishers");
const BodyHandlers = Java.type("java.net.http.HttpResponse.BodyHandlers");
const fetch = function(req) {
const client = HttpClient.newBuilder().build();
let requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(req.url))
.method(req.method, req.body ?
BodyPublishers.ofString(req.body) :
BodyPublishers.noBody());
if(req.headers) {
for(var key in req.headers) {
if(req.headers.hasOwnProperty(key)) {
requestBuilder.header(key, req.headers[key]);
}
}
}
const response = client.send(requestBuilder.build(), BodyHandlers.ofString());
return {
status: response.statusCode(),
body: function() {
return response.body();
},
headers: response.headers().map()
};
}
Number.isInteger = function(value) {
if (typeof value !== 'number') {
return false;
}
if (!isFinite(value)) {
return false;
}
return Math.floor(value) === value;
};
Uint8Array.prototype.slice = function(start, end) {
if (end === undefined) {
end = this.length;
}
var newArray = new Uint8Array(end - start);
for (var i = start; i < end; i++) {
newArray[i - start] = this[i];
}
return newArray;
};
function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
}
function BigInt(value) {
// 如果已经是 BigInteger 类型,直接返回
if (value instanceof BigInteger) {
return value;
}
if (typeof value === 'string') {
// 处理十六进制字符串
if (value.startsWith('0x')) {
return new BigInteger(value.substring(2), 16);
}
// 处理普通数字字符串
return new BigInteger(value, 10);
}
if (typeof value === 'number') {
return new BigInteger(value.toString(), 10);
}
// 处理布尔值
if (typeof value === 'boolean') {
return new BigInteger(value ? "1" : "0", 10);
}
throw new Error("Cannot convert " + value + " to BigInt");
}
const BN_0$a = BigInt(0);
const BN_1$5 = BigInt(1);
const Nibbles$1 = "0123456789abcdef";
function toBigInt(value) {
if (value instanceof Uint8Array) {
let result = "0x0";
for (let i = 0; i < value.length; i++) {
let v = value[i];
result += Nibbles$1[v >> 4];
result += Nibbles$1[v & 0x0f];
}
return BigInt(result);
}
return getBigInt(value);
}
function toNumber(value) {
return getNumber(toBigInt(value));
}
function isError(error, code) {
return (error && error.code === code);
};
function isCallException(error) {
return isError(error, "CALL_EXCEPTION");
};
function Proxy(target, fns) {
return {
__noSuchProperty__: function(prop) {
return fns.get(target, prop, null);
}
};
}
Object.assign = function(target) {
// 检查target是否为null或undefined
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
// 将target转换为对象
var to = Object(target);
// 遍历所有源对象
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
// 跳过null和undefined的源对象
if (nextSource != null) {
// 遍历源对象的所有可枚举属性
for (var nextKey in nextSource) {
// 确保是对象自身的属性而不是原型链上的
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
}
const resultNames = new WeakMap();
function getNames(result) {
return resultNames.get(result);
}
function setNames(result, names) {
resultNames.set(result, names);
}
function concat(datas) {
return "0x" + datas.map((d) => hexlify(d).substring(2)).join("");
}
function isHexString(value, length) {
if (typeof (value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {
return false;
}
if (typeof (length) == "number" && value.length !== 2 + 2 * length) {
return false;
}
if (length === true && (value.length % 2) !== 0) {
return false;
}
return true;
}
/**
* Returns true if %%value%% is a valid representation of arbitrary
* data (i.e. a valid [[DataHexString]] or a Uint8Array).
*/
function isBytesLike(value) {
return (isHexString(value, true) || (value instanceof Uint8Array));
}
function assertPrivate(givenGuard, guard, className) {
if(className == null) {
className = "";
}
if(givenGuard !== guard) {
let method = className, operation = "new";
if(className) {
method += ".";
operation += " " + className;
}
assert(false, `private constructor; use ${method}from* methods`, "UNSUPPORTED_OPERATION", {
operation: operation
});
}
}
function _getBytes(value, name, copy) {
if (value instanceof Uint8Array) {
if (copy) {
return new Uint8Array(value);
}
return value;
}
if (typeof (value) === "string" && value.match(/^0x(?:[0-9a-f][0-9a-f])*$/i)) {
const result = new Uint8Array((value.length - 2) / 2);
let offset = 2;
for (let i = 0; i < result.length; i++) {
result[i] = parseInt(value.substring(offset, offset + 2), 16);
offset += 2;
}
return result;
}
assertArgument(false, "invalid BytesLike value", name || "value", value);
}
/**
* Get a typed Uint8Array for %%value%%. If already a Uint8Array
* the original %%value%% is returned; if a copy is required use
* [[getBytesCopy]].
*
* @see: getBytesCopy
*/
function getBytes(value, name) {
return _getBytes(value, name, false);
}
/**
* Get a typed Uint8Array for %%value%%, creating a copy if necessary
* to prevent any modifications of the returned value from being
* reflected elsewhere.
*
* @see: getBytes
*/
function getBytesCopy(value, name) {
return _getBytes(value, name, true);
}
function getBigInt(value, name) {
if(value instanceof BigInteger){
return value;
}
switch (typeof (value)) {
case "bigint": return value;
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return BigInt(value);
case "string":
try {
if (value === "") {
throw new Error("empty string");
}
if (value[0] === "-" && value[1] !== "-") {
return -BigInt(value.substring(1));
}
return BigInt(value);
}
catch (e) {
assertArgument(false, `invalid BigNumberish string: ${e.message}`, name || "value", value);
}
}
assertArgument(false, "invalid BigNumberish value", name || "value", value);
}
/**
* Returns %%value%% as a bigint, validating it is valid as a bigint
* value and that it is positive.
*/
function getUint(value, name) {
const result = getBigInt(value, name);
assert(result >= BN_0$a, "unsigned value cannot be negative", "NUMERIC_FAULT", {
fault: "overflow", operation: "getUint", value: value
});
return result;
}
function uint8ArrayToByteArray(uint8Array) {
var bytes = new ByteArray(uint8Array.length);
for (var i = 0; i < uint8Array.length; i++) {
bytes[i] = uint8Array[i];
}
return bytes;
}
function byteArrayToUint8Array(byteArray) {
var uint8Array = new Uint8Array(byteArray.length);
for (var i = 0; i < byteArray.length; i++) {
uint8Array[i] = byteArray[i] & 0xFF; // 使用位运算确保值在0-255范围内
}
return uint8Array;
}
function hexlify(data) {
const HexCharacters = "0123456789abcdef";
// 添加 getBytes 确保数据格式正确
const bytes = getBytes(data);
let result = "0x";
for (let i = 0; i < bytes.length; i++) {
const v = bytes[i] & 0xFF;
result += HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f];
}
return result;
}
function checkType(value, type, name) {
const types = type.split("|").map(t => t.trim());
for (let i = 0; i < types.length; i++) {
switch (type) {
case "any":
return;
case "bigint":
if(value instanceof BigInteger) return;
case "boolean":
case "number":
case "string":
if (typeof (value) === type) {
return;
}
}
}
const error = new Error(`invalid value for type ${type}`);
error.code = "INVALID_ARGUMENT";
error.argument = `value.${name}`;
error.value = value;
throw error;
};
function keccak256(_data) {
try {
var data = getBytes(_data, 'data');
// 使用 BouncyCastle 的 Keccak-256
var md = MessageDigest.getInstance("Keccak-256", "BC");
var hash = md.digest(uint8ArrayToByteArray(data));
return hexlify(byteArrayToUint8Array(hash));
} catch (e) {
throw new Error('Failed to compute keccak256: ' + e.message);
}
}
function id(value) {
return keccak256(toUtf8Bytes(value));
}
//export
function _toUtf8String(codePoints) {
return codePoints.map((codePoint) => {
if (codePoint <= 0xffff) {
return String.fromCharCode(codePoint);
}
codePoint -= 0x10000;
return String.fromCharCode((((codePoint >> 10) & 0x3ff) + 0xd800), ((codePoint & 0x3ff) + 0xdc00));
}).join("");
}
/**
* Returns the string represented by the UTF-8 data %%bytes%%.
*
* When %%onError%% function is specified, it is called on UTF-8
* errors allowing recovery using the [[Utf8ErrorFunc]] API.
* (default: [error](Utf8ErrorFuncs))
*/
function toUtf8String(bytes, onError) {
return _toUtf8String(getUtf8CodePoints(bytes, onError));
}
/**
* Returns the UTF-8 code-points for %%str%%.
*
* If %%form%% is specified, the string is normalized.
*/
function toUtf8CodePoints(str, form) {
return getUtf8CodePoints(toUtf8Bytes(str, form));
}
function errorFunc(reason, offset, bytes, output, badCodepoint) {
assertArgument(false, `invalid codepoint at offset ${offset}; ${reason}`, "bytes", bytes);
}
function ignoreFunc(reason, offset, bytes, output, badCodepoint) {
// If there is an invalid prefix (including stray continuation), skip any additional continuation bytes
if (reason === "BAD_PREFIX" || reason === "UNEXPECTED_CONTINUE") {
let i = 0;
for (let o = offset + 1; o < bytes.length; o++) {
if (bytes[o] >> 6 !== 0x02) {
break;
}
i++;
}
return i;
}
// This byte runs us past the end of the string, so just jump to the end
// (but the first byte was read already read and therefore skipped)
if (reason === "OVERRUN") {
return bytes.length - offset - 1;
}
// Nothing to skip
return 0;
}
function replaceFunc(reason, offset, bytes, output, badCodepoint) {
// Overlong representations are otherwise "valid" code points; just non-deistingtished
if (reason === "OVERLONG") {
assertArgument(typeof (badCodepoint) === "number", "invalid bad code point for replacement", "badCodepoint", badCodepoint);
output.push(badCodepoint);
return 0;
}
// Put the replacement character into the output
output.push(0xfffd);
// Otherwise, process as if ignoring errors
return ignoreFunc(reason, offset, bytes);
}
const Utf8ErrorFuncs = Object.freeze({
error: errorFunc,
ignore: ignoreFunc,
replace: replaceFunc
});
// http://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript#13691499
function getUtf8CodePoints(_bytes, onError) {
if (onError == null) {
onError = Utf8ErrorFuncs.error;
}
const bytes = getBytes(_bytes, "bytes");
const result = [];
let i = 0;
// Invalid bytes are ignored
while (i < bytes.length) {
const c = bytes[i++];
// 0xxx xxxx
if (c >> 7 === 0) {
result.push(c);
continue;
}
// Multibyte; how many bytes left for this character?
let extraLength = null;
let overlongMask = null;
// 110x xxxx 10xx xxxx
if ((c & 0xe0) === 0xc0) {
extraLength = 1;
overlongMask = 0x7f;
// 1110 xxxx 10xx xxxx 10xx xxxx
}
else if ((c & 0xf0) === 0xe0) {
extraLength = 2;
overlongMask = 0x7ff;
// 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
}
else if ((c & 0xf8) === 0xf0) {
extraLength = 3;
overlongMask = 0xffff;
}
else {
if ((c & 0xc0) === 0x80) {
i += onError("UNEXPECTED_CONTINUE", i - 1, bytes, result);
}
else {
i += onError("BAD_PREFIX", i - 1, bytes, result);
}
continue;
}
// Do we have enough bytes in our data?
if (i - 1 + extraLength >= bytes.length) {
i += onError("OVERRUN", i - 1, bytes, result);
continue;
}
// Remove the length prefix from the char
let res = c & ((1 << (8 - extraLength - 1)) - 1);
for (let j = 0; j < extraLength; j++) {
let nextChar = bytes[i];
// Invalid continuation byte
if ((nextChar & 0xc0) != 0x80) {
i += onError("MISSING_CONTINUE", i, bytes, result);
res = null;
break;
}
res = (res << 6) | (nextChar & 0x3f);
i++;
}
// See above loop for invalid continuation byte
if (res === null) {
continue;
}
// Maximum code point
if (res > 0x10ffff) {
i += onError("OUT_OF_RANGE", i - 1 - extraLength, bytes, result, res);
continue;
}
// Reserved for UTF-16 surrogate halves
if (res >= 0xd800 && res <= 0xdfff) {
i += onError("UTF16_SURROGATE", i - 1 - extraLength, bytes, result, res);
continue;
}
// Check for overlong sequences (more bytes than needed)
if (res <= overlongMask) {
i += onError("OVERLONG", i - 1 - extraLength, bytes, result, res);
continue;
}
result.push(res);
}
return result;
}
function toUtf8Bytes(str, form) {
assertArgument(typeof (str) === "string", "invalid string value", "str", str);
if (form != null) {
assertNormalize(form);
str = str.normalize(form);
}
let result = [];
for (let i = 0; i < str.length; i++) {
const c = str.charCodeAt(i);
if (c < 0x80) {
result.push(c);
}
else if (c < 0x800) {
result.push((c >> 6) | 0xc0);
result.push((c & 0x3f) | 0x80);
}
else if ((c & 0xfc00) === 0xd800) {
i++;
const c2 = str.charCodeAt(i);
assertArgument(i < str.length && ((c2 & 0xfc00) === 0xdc00), "invalid surrogate pair", "str", str);
// Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
result.push((pair >> 18) | 0xf0);
result.push(((pair >> 12) & 0x3f) | 0x80);
result.push(((pair >> 6) & 0x3f) | 0x80);
result.push((pair & 0x3f) | 0x80);
}
else {
result.push((c >> 12) | 0xe0);
result.push(((c >> 6) & 0x3f) | 0x80);
result.push((c & 0x3f) | 0x80);
}
}
return new Uint8Array(result);
}
function getChecksumAddress(address) {
address = address.toLowerCase();
const chars = address.substring(2).split("");
const expanded = new Uint8Array(40);
for (let i = 0; i < 40; i++) {
expanded[i] = chars[i].charCodeAt(0);
}
const hashed = getBytes(keccak256(expanded));
for (let i = 0; i < 40; i += 2) {
if ((hashed[i >> 1] >> 4) >= 8) {
chars[i] = chars[i].toUpperCase();
}
if ((hashed[i >> 1] & 0x0f) >= 8) {
chars[i + 1] = chars[i + 1].toUpperCase();
}
}
return "0x" + chars.join("");
}
function getAddress(address) {
assertArgument(typeof (address) === "string", "invalid address", "address", address);
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
// Missing the 0x prefix
if (!address.startsWith("0x")) {
address = "0x" + address;
}
const result = getChecksumAddress(address);
// It is a checksummed address with a bad checksum
assertArgument(!address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) || result === address, "bad address checksum", "address", address);
return result;
}
// Maybe ICAP? (we only support direct mode)
if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
// It is an ICAP address with a bad checksum
assertArgument(address.substring(2, 4) === ibanChecksum(address), "bad icap checksum", "address", address);
let result = fromBase36(address.substring(4)).toString(16);
while (result.length < 40) {
result = "0" + result;
}
return getChecksumAddress("0x" + result);
}
assertArgument(false, "invalid address", "address", address);
}
function resolveAddress(target, resolver) {
if (typeof (target) === "string") {
if (target.match(/^0x[0-9a-f]{40}$/i)) {
return getAddress(target);
}
assert(resolver != null, "ENS resolution requires a provider", "UNSUPPORTED_OPERATION", { operation: "resolveName" });
return checkAddress(target, resolver.resolveName(target));
}
else if (isAddressable(target)) {
return checkAddress(target, target.getAddress());
}
else if (target && typeof (target.then) === "function") {
return checkAddress(target, target);
}
assertArgument(false, "unsupported addressable value", "target", target);
}
function resolveArgs(_runner, inputs, args) {
// Recursively descend into args and resolve any addresses
const runner = getRunner(_runner, "resolveName");
const resolver = canResolve(runner) ? runner : null;
return inputs.map((param, index) => {
return param.walkAsync(args[index], (type, value) => {
value = Typed.dereference(value, type);
if (type === "address") {
return resolveAddress(value, resolver);
}
return value;
});
});
}
function canResolve(value) {
return (value && typeof (value.resolveName) === "function");
}
function canCall(value) {
return (value && typeof (value.call) === "function");
}
function canEstimate(value) {
return (value && typeof (value.estimateGas) === "function");
}
function getRunner(value, feature) {
if (value == null) {
return null;
}
if (typeof (value[feature]) === "function") {
return value;
}
if (value.provider && typeof (value.provider[feature]) === "function") {
return value.provider;
}
return null;
}
function buildWrappedMethod(contract, key) {
var getFragment = function () {
var args = Array.prototype.slice.call(arguments);
var fragment = contract.interface.getFunction(key, args);
assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
operation: "fragment",
info: { key: key, args: args }
});
return fragment;
};
var populateTransaction = function () {
var args = Array.prototype.slice.call(arguments);
var fragment = getFragment.apply(null, args);
// If an overrides was passed in, copy it and normalize the values
var overrides = {};
if (fragment.inputs.length + 1 === args.length) {
overrides = copyOverrides(args.pop());
if (overrides.from) {
overrides.from = resolveAddress(overrides.from, getResolver(contract.runner));
}
}
if (fragment.inputs.length !== args.length) {
throw new Error("internal error: fragment inputs doesn't match arguments; should not happen");
}
var resolvedArgs = resolveArgs(contract.runner, fragment.inputs, args);
return Object.assign({}, overrides, {
to: contract.getAddress(),
data: contract.interface.encodeFunctionData(fragment, resolvedArgs)
});
};
var staticCall = function () {
var args = Array.prototype.slice.call(arguments);
var result = staticCallResult.apply(null, args);
if (result.length === 1) {
return result[0];
}
return result;
};
var send = function () {
var args = Array.prototype.slice.call(arguments);
var runner = contract.runner;
assert(canSend(runner), "contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", { operation: "sendTransaction" });
var tx = runner.sendTransaction(populateTransaction.apply(null, args));
var provider = getProvider(contract.runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
return new ContractTransactionResponse(contract.interface, provider, tx);
};
var estimateGas = function () {
var args = Array.prototype.slice.call(arguments);
var runner = getRunner(contract.runner, "estimateGas");
assert(canEstimate(runner), "contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", { operation: "estimateGas" });
return runner.estimateGas(populateTransaction.apply(null, args));
};
var staticCallResult = function () {
var args = Array.prototype.slice.call(arguments);
var runner = getRunner(contract.runner, "call");
assert(canCall(runner), "contract runner does not support calling", "UNSUPPORTED_OPERATION", { operation: "call" });
var tx = populateTransaction.apply(null, args);
var result = "0x";
try {
result = runner.call(tx);
}
catch (error) {
if (isCallException(error) && error.data) {
throw contract.interface.makeError(error.data, tx);
}
throw error;
}
var fragment = getFragment.apply(null, args);
return contract.interface.decodeFunctionResult(fragment, result);
};
var method = function () {
var args = Array.prototype.slice.call(arguments);
var fragment = getFragment.apply(null, args);
if (fragment.constant) {
return staticCall.apply(null, args);
}
return send.apply(null, args);
};
defineProperties(method, {
methodName: contract.interface.getFunctionName(key),
_contract: contract,
_key: key,
getFragment: getFragment,
estimateGas: estimateGas,
populateTransaction: populateTransaction,
send: send,
staticCall: staticCall,
staticCallResult: staticCallResult
});
// Only works on non-ambiguous keys (refined fragment is always non-ambiguous)
Object.defineProperty(method, "fragment", {
configurable: false,
enumerable: true,
get: function() {
var fragment = contract.interface.getFunction(key);
assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
operation: "fragment",
info: { key: key }
});
return fragment;
}
});
return method;
}
function buildWrappedEvent(contract, key) {
var getFragment = function() {
var args = Array.prototype.slice.call(arguments);
var fragment = contract.interface.getEvent(key, args);
assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
operation: "fragment",
info: { key: key, args: args }
});
return fragment;
};
var method = function() {
var args = Array.prototype.slice.call(arguments);
return new PreparedTopicFilter(contract, getFragment.apply(null, args), args);
};
defineProperties(method, {
name: contract.interface.getEventName(key),
_contract: contract,
_key: key,
getFragment: getFragment
});
// Only works on non-ambiguous keys (refined fragment is always non-ambiguous)
Object.defineProperty(method, "fragment", {
configurable: false,
enumerable: true,
get: function() {
var fragment = contract.interface.getEvent(key);
assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
operation: "fragment",
info: { key: key }
});
return fragment;
}
});
return method;
}
function allowSingle(set, allowed) {
let included = [];
for (const key in allowed.keys()) {
if (set.has(key)) {
included.push(key);
}
}
if (included.length > 1) {
throw new Error(`conflicting types: ${included.join(", ")}`);
}
}
// Functions to process a Solidity Signature TokenString from left-to-right for...
// ...the name with an optional type, returning the name
function consumeName(type, tokens) {
if (tokens.peekKeyword(KwTypes)) {
const keyword = tokens.pop().text;
if (keyword !== type) {
throw new Error(`expected ${type}, got ${keyword}`);
}
}
return tokens.popType("ID");
}
// ...all keywords matching allowed, returning the keywords
function consumeKeywords(tokens, allowed) {
const keywords = new Set();
while (true) {
const keyword = tokens.peekType("KEYWORD");
if (keyword == null || (allowed && !allowed.has(keyword))) {
break;
}
tokens.pop();
if (keywords.has(keyword)) {
throw new Error(`duplicate keywords: ${JSON.stringify(keyword)}`);
}
keywords.add(keyword);
}
return Object.freeze(keywords);
}
// ...all visibility keywords, returning the coalesced mutability
function consumeMutability(tokens) {
let modifiers = consumeKeywords(tokens, KwVisib);
// Detect conflicting modifiers
allowSingle(modifiers, setify("constant payable nonpayable".split(" ")));
allowSingle(modifiers, setify("pure view payable nonpayable".split(" ")));
// Process mutability states
if (modifiers.has("view")) {
return "view";
}
if (modifiers.has("pure")) {
return "pure";
}
if (modifiers.has("payable")) {
return "payable";
}
if (modifiers.has("nonpayable")) {
return "nonpayable";
}
// Process legacy `constant` last
if (modifiers.has("constant")) {
return "view";
}
return "nonpayable";
}
// ...a parameter list, returning the ParamType list
function consumeParams(tokens, allowIndexed) {
return tokens.popParams().map((t) => ParamType.from(t, allowIndexed));
}
// ...a gas limit, returning a BigNumber or null if none
function consumeGas(tokens) {
if (tokens.peekType("AT")) {
tokens.pop();
if (tokens.peekType("NUMBER")) {
return getBigInt(tokens.pop().text);
}
throw new Error("invalid gas");
}
return null;
}
function consumeEoi(tokens) {
if (tokens.length) {
throw new Error(`unexpected tokens at offset ${tokens.offset}: ${tokens.toString()}`);
}
}
function verifyBasicType(type) {
const match = type.match(regexType);
assertArgument(match, "invalid type", "type", type);
if (type === "uint") {
return "uint256";
}
if (type === "int") {
return "int256";
}
if (match[2]) {
// bytesXX
const length = parseInt(match[2]);
assertArgument(length !== 0 && length <= 32, "invalid bytes length", "type", type);
}
else if (match[3]) {
// intXX or uintXX
const size = parseInt(match[3]);
assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid numeric width", "type", type);
}
return type;
}
function stringify(value) {
if (value == null) {
return "null";
}
if (Array.isArray(value)) {
return "[ " + (value.map(stringify)).join(", ") + " ]";
}
if (value instanceof Uint8Array) {
const HEX = "0123456789abcdef";
let result = "0x";
for (let i = 0; i < value.length; i++) {
result += HEX[value[i] >> 4];
result += HEX[value[i] & 0xf];
}
return result;
}
if (typeof (value) === "object" && typeof (value.toJSON) === "function") {
return stringify(value.toJSON());
}
if (value instanceof BigInteger) {
return value.toString();
}
switch (typeof (value)) {
case "boolean":
case "symbol":
return value.toString();
case "bigint":
return BigInt(value).toString();
case "number":
return (value).toString();
case "string":
return JSON.stringify(value);
case "object": {
const keys = Object.keys(value);
keys.sort();
return "{ " + keys.map((k) => `${stringify(k)}: ${stringify(value[k])}`).join(", ") + " }";
}
}
return `[ COULD NOT SERIALIZE ]`;
};
function makeError(message, code, info) {
var shortMessage = message;
{
var details = [];
if (info) {
if ("message" in info || "code" in info || "name" in info) {
throw new Error("value will overwrite populated values: " + stringify(info));
}
for (var key in info) {
if (key === "shortMessage") {
continue;
}
var value = (info[key]);
details.push(key + "=" + stringify(value));
}
}
details.push("code=" + code);
details.push("version=" + version);
if (details.length) {
message += " (" + details.join(", ") + ")";
}
}
var error;
switch (code) {
case "INVALID_ARGUMENT":
error = new TypeError(message);
break;
case "NUMERIC_FAULT":
case "BUFFER_OVERRUN":
error = new RangeError(message);
break;
default:
error = new Error(message);
}
defineProperties(error, { code: code });
if (info) {
Object.assign(error, info);
}
if (error.shortMessage == null) {
defineProperties(error, { shortMessage: shortMessage });
}
return error;
};
function defineProperties(target, values, types) {
for (let key in values) {
let value = values[key];
const type = (types ? types[key] : null);
if (type) {
checkType(value, type, key);
}
Object.defineProperty(target, key, { enumerable: true, value: value, writable: false });
}
};
function assert(check, message, code, info) {
if (!check) {
throw makeError(message, code, info);
}
};
function assertArgument(check, message, name, value) {
assert(check, message, "INVALID_ARGUMENT", { argument: name, value: value });
}
function assertArgumentCount(count, expectedCount, message) {
if (message == null) {
message = "";
}
if (message) {
message = ": " + message;
}
assert(count >= expectedCount, "missing arguemnt" + message, "MISSING_ARGUMENT", {
count: count,
expectedCount: expectedCount
});
assert(count <= expectedCount, "too many arguments" + message, "UNEXPECTED_ARGUMENT", {
count: count,
expectedCount: expectedCount
});
}
function toBeArray(_value) {
const value = getUint(_value, "value");
if (value === BN_0$a) {
return new Uint8Array([]);
}
let hex = value.toString(16);
if (hex.length % 2) {
hex = "0" + hex;
}
const result = new Uint8Array(hex.length / 2);
for (let i = 0; i < result.length; i++) {
const offset = i * 2;
result[i] = parseInt(hex.substring(offset, offset + 2), 16);
}
return result;
}
function getValue$1(value) {
let bytes = toBeArray(value);
assert(bytes.length <= WordSize, "value out-of-bounds", "BUFFER_OVERRUN", { buffer: bytes, length: WordSize, offset: bytes.length });
if (bytes.length !== WordSize) {
bytes = getBytesCopy(concat([Padding.slice(bytes.length % WordSize), bytes]));
}
return bytes;
}
function lex(text) {
const tokens = [];
const throwError = (message) => {
const token = (offset < text.length) ? JSON.stringify(text[offset]) : "$EOI";
throw new Error(`invalid token ${token} at ${offset}: ${message}`);
};
let brackets = [];
let commas = [];
let offset = 0;
while (offset < text.length) {
// Strip off any leading whitespace
let cur = text.substring(offset);
let match = cur.match(regexWhitespacePrefix);
if (match) {
offset += match[1].length;
cur = text.substring(offset);
}
const token = { depth: brackets.length, linkBack: -1, linkNext: -1, match: -1, type: "", text: "", offset: offset, value: -1 };
tokens.push(token);
let type = (SimpleTokens[cur[0]] || "");
if (type) {
token.type = type;
token.text = cur[0];
offset++;
if (type === "OPEN_PAREN") {
brackets.push(tokens.length - 1);
commas.push(tokens.length - 1);
}
else if (type === "CLOSE_PAREN") {
if (brackets.length === 0) {
throwError("no matching open bracket");
}
token.match = brackets.pop();
(tokens[token.match]).match = tokens.length - 1;
token.depth--;
token.linkBack = commas.pop();
(tokens[token.linkBack]).linkNext = tokens.length - 1;
}
else if (type === "COMMA") {
token.linkBack = commas.pop();
(tokens[token.linkBack]).linkNext = tokens.length - 1;
commas.push(tokens.length - 1);
}
else if (type === "OPEN_BRACKET") {
token.type = "BRACKET";
}
else if (type === "CLOSE_BRACKET") {
// Remove the CLOSE_BRACKET
let suffix = tokens.pop().text;
if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") {
const value = tokens.pop().text;
suffix = value + suffix;
(tokens[tokens.length - 1]).value = getNumber(value);
}
if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") {
throw new Error("missing opening bracket");
}
(tokens[tokens.length - 1]).text += suffix;
}
continue;
}
match = cur.match(regexIdPrefix);
if (match) {
token.text = match[1];
offset += token.text.length;
if (Keywords.has(token.text)) {
token.type = "KEYWORD";
continue;
}
if (token.text.match(regexType)) {
token.type = "TYPE";
continue;
}
token.type = "ID";
continue;
}
match = cur.match(regexNumberPrefix);
if (match) {
token.text = match[1];
token.type = "NUMBER";
offset += token.text.length;
continue;
}
throw new Error(`unexpected token ${JSON.stringify(cur[0])} at position ${offset}`);
}
return new TokenString(tokens.map((t) => Object.freeze(t)));
}
const _guard$2 = {};
const _gaurd = {};
const passProperties = ["then"];
const _typedSymbol = "_ethers_typed";
const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/);
const internal = "_ethers_internal";
const ParamTypeInternal = "_ParamTypeInternal";
const ErrorFragmentInternal = "_ErrorInternal";
const EventFragmentInternal = "_EventInternal";
const ConstructorFragmentInternal = "_ConstructorInternal";
const FallbackFragmentInternal = "_FallbackInternal";
const FunctionFragmentInternal = "_FunctionInternal";
const StructFragmentInternal = "_StructInternal";
function setify(items) {
const result = new Set();
items.forEach((k) => result.add(k));
return Object.freeze(result);
}
const _kwVisibDeploy = "external public payable override";
const KwVisibDeploy = setify(_kwVisibDeploy.split(" "));
// Visibility Keywords
const _kwVisib = "constant external internal payable private public pure view override";
const KwVisib = setify(_kwVisib.split(" "));
const _kwTypes = "constructor error event fallback function receive struct";
const KwTypes = setify(_kwTypes.split(" "));
const _kwModifiers = "calldata memory storage payable indexed";
const KwModifiers = setify(_kwModifiers.split(" "));
const _kwOther = "tuple returns";
// All Keywords
const _keywords = [_kwTypes, _kwModifiers, _kwOther, _kwVisib].join(" ");
const Keywords = setify(_keywords.split(" "));
// Single character tokens
const SimpleTokens = {
"(": "OPEN_PAREN", ")": "CLOSE_PAREN",
"[": "OPEN_BRACKET", "]": "CLOSE_BRACKET",
",": "COMMA", "@": "AT"
};
// Parser regexes to consume the next token
const regexWhitespacePrefix = new RegExp("^(\\s*)");
const regexNumberPrefix = new RegExp("^([0-9]+)");
const regexIdPrefix = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)");
// Parser regexs to check validity
const regexId = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)$");
const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))$");
function ParamType(guard, name, type, baseType, indexed, components, arrayLength, arrayChildren) {
assertPrivate(guard, _guard$2, "ParamType");
Object.defineProperty(this, internal, { value: ParamTypeInternal });
if (components) {
components = Object.freeze(components.slice());
}
if (baseType === "array") {
if (arrayLength == null || arrayChildren == null) {
throw new Error("");
}
}
else if (arrayLength != null || arrayChildren != null) {
throw new Error("");
}
if (baseType === "tuple") {
if (components == null) {
throw new Error("");
}
}
else if (components != null) {
throw new Error("");
}
defineProperties(this, {
name: name,
type: type,
baseType: baseType,
indexed: indexed,
components: components,
arrayLength: arrayLength,
arrayChildren: arrayChildren
});
}
ParamType.prototype.format = function(format) {
if (format == null) {
format = "sighash";
}
if (format === "json") {
var name = this.name || "";
if (this.isArray()) {
var result = JSON.parse(this.arrayChildren.format("json"));
result.name = name;
result.type += "[" + (this.arrayLength < 0 ? "" : String(this.arrayLength)) + "]";
return JSON.stringify(result);
}
var result = {
type: ((this.baseType === "tuple") ? "tuple" : this.type),
name: name
};
if (typeof (this.indexed) === "boolean") {
result.indexed = this.indexed;
}
if (this.isTuple()) {
result.components = this.components.map(function(c) {
return JSON.parse(c.format(format));
});
}
return JSON.stringify(result);
}
var result = "";
// Array
if (this.isArray()) {
result += this.arrayChildren.format(format);
result += "[" + (this.arrayLength < 0 ? "" : String(this.arrayLength)) + "]";
}
else {
if (this.isTuple()) {
result += "(" + this.components.map(function(comp) {
return comp.format(format);
}).join((format === "full") ? ", " : ",") + ")";
}
else {
result += this.type;
}
}
if (format !== "sighash") {
if (this.indexed === true) {
result += " indexed";
}
if (format === "full" && this.name) {
result += " " + this.name;
}
}
return result;
};
ParamType.prototype.isArray = function() {
return (this.baseType === "array");
};
ParamType.prototype.isTuple = function() {
return (this.baseType === "tuple");
};
ParamType.prototype.isIndexable = function() {
return (this.indexed != null);
};
ParamType.prototype.walk = function(value, process) {
if (this.isArray()) {
if (!Array.isArray(value)) {
throw new Error("invalid array value");
}
if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
throw new Error("array is wrong length");
}
var _this = this;
return value.map(function(v) {
return _this.arrayChildren.walk(v, process);
});
}
if (this.isTuple()) {
if (!Array.isArray(value)) {
throw new Error("invalid tuple value");
}
if (value.length !== this.components.length) {
throw new Error("array is wrong length");
}
var _this = this;
return value.map(function(v, i) {
return _this.components[i].walk(v, process);
});
}
return process(this.type, value);
};
ParamType.prototype._walkAsync = function(promises, value, process, setValue) {
if (this.isArray()) {
if (!Array.isArray(value)) {
throw new Error("invalid array value");
}
if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
throw new Error("array is wrong length");
}
var childType = this.arrayChildren;
var result = value.slice();
result.forEach(function(value, index) {
childType._walkAsync(promises, value, process, function(value) {
result[index] = value;
});
});
setValue(result);
return;
}
if (this.isTuple()) {
var components = this.components;
// Convert the object into an array
var result;
if (Array.isArray(value)) {
result = value.slice();
}
else {
if (value == null || typeof (value) !== "object") {
throw new Error("invalid tuple value");
}
result = components.map(function(param) {
if (!param.name) {
throw new Error("cannot use object value with unnamed components");
}
if (!(param.name in value)) {
throw new Error("missing value for component " + param.name);
}
return value[param.name];
});
}
if (result.length !== this.components.length) {
throw new Error("array is wrong length, " + result.length + ", " + this.components.length);
}
var _this = this;
result.forEach(function(value, index) {
components[index]._walkAsync(promises, value, process, function(value) {
result[index] = value;
});
});
setValue(result);
return;
}
var result = process(this.type, value);
setValue(result);
};
ParamType.prototype.walkAsync = function(value, process) {
var result = [value];
this._walkAsync([], value, process, function(value) {
result[0] = value;
});
return result[0];
};
ParamType.from = function(obj, allowIndexed) {
if (ParamType.isParamType(obj)) {
return obj;
}
if (typeof (obj) === "string") {
try {
return ParamType.from(lex(obj), allowIndexed);
}
catch (error) {
assertArgument(false, "invalid param type", "obj", obj);
}
}
else if (obj instanceof TokenString) {
var type = "", baseType = "";
var comps = null;
if (consumeKeywords(obj, setify(["tuple"])).has("tuple") || obj.peekType("OPEN_PAREN")) {
// Tuple
baseType = "tuple";
comps = obj.popParams().map(function(t) {
return ParamType.from(t);
});
type = "tuple(" + comps.map(function(c) {
return c.format();
}).join(",") + ")";
}
else {
// Normal
type = verifyBasicType(obj.popType("TYPE"));
baseType = type;
}
// Check for Array
var arrayChildren = null;
var arrayLength = null;
while (obj.length && obj.peekType("BRACKET")) {
var bracket = obj.pop(); //arrays[i];
arrayChildren = new ParamType(_guard$2, "", type, baseType, null, comps, arrayLength, arrayChildren);
arrayLength = bracket.value;
type += bracket.text;
baseType = "array";
comps = null;
}
var indexed = null;
var keywords = consumeKeywords(obj, KwModifiers);
if (keywords.has("indexed")) {
if (!allowIndexed) {
throw new Error("");
}
indexed = true;
}
var name = (obj.peekType("ID") ? obj.pop().text : "");
if (obj.length) {
throw new Error("leftover tokens");
}
return new ParamType(_guard$2, name, type, baseType, indexed, comps, arrayLength, arrayChildren);
}
var name = obj.name;
assertArgument(!name || (typeof (name) === "string" && name.match(regexId)), "invalid name", "obj.name", name);
var indexed = obj.indexed;
if (indexed != null) {
assertArgument(allowIndexed, "parameter cannot be indexed", "obj.indexed", obj.indexed);
indexed = !!indexed;
}
var type = obj.type;
var arrayMatch = type.match(regexArrayType);
if (arrayMatch) {
var arrayLength = parseInt(arrayMatch[2] || "-1");
var arrayChildren = ParamType.from({
type: arrayMatch[1],
components: obj.components
});
return new ParamType(_guard$2, name || "", type, "array", indexed, null, arrayLength, arrayChildren);
}
if (type === "tuple" || type.startsWith("tuple(") || type.startsWith("(")) {
var comps = (obj.components != null) ? obj.components.map(function(c) {
return ParamType.from(c);
}) : null;
var tuple = new ParamType(_guard$2, name || "", type, "tuple", indexed, comps, null, null);
// @TODO: use lexer to validate and normalize type
return tuple;
}
type = verifyBasicType(obj.type);
return new ParamType(_guard$2, name || "", type, type, indexed, null, null, null);
};
ParamType.isParamType = function(value) {
return (value && value[internal] === ParamTypeInternal);
};
function TokenString(tokens) {
var _offset = 0;
var _tokens = tokens.slice();
Object.defineProperty(this, 'offset', {
get: function() { return _offset; }
});
Object.defineProperty(this, 'length', {
get: function() { return _tokens.length - _offset; }
});
this.clone = function() {
return new TokenString(_tokens);
};
this.reset = function() {
_offset = 0;
};
function subTokenString(from, to) {
if (from === undefined) from = 0;
if (to === undefined) to = 0;
return new TokenString(_tokens.slice(from, to).map(function(t) {
return Object.freeze(Object.assign({}, t, {
match: (t.match - from),
linkBack: (t.linkBack - from),
linkNext: (t.linkNext - from),
}));
}));
}
this.popKeyword = function(allowed) {
var top = this.peek();
if (top.type !== "KEYWORD" || !allowed.has(top.text)) {
throw new Error("expected keyword " + top.text);
}
return this.pop().text;
};
this.popType = function(type) {
if (this.peek().type !== type) {
var top = this.peek();
throw new Error("expected " + type + "; got " + top.type + " " + JSON.stringify(top.text));
}
return this.pop().text;
};
this.popParen = function() {
var top = this.peek();
if (top.type !== "OPEN_PAREN") {
throw new Error("bad start");
}
var result = subTokenString(_offset + 1, top.match + 1);
_offset = top.match + 1;
return result;
};
this.popParams = function() {
var top = this.peek();
if (top.type !== "OPEN_PAREN") {
throw new Error("bad start");
}
var result = [];
while (_offset < top.match - 1) {
var link = this.peek().linkNext;
result.push(subTokenString(_offset + 1, link));
_offset = link;
}
_offset = top.match + 1;
return result;
};
this.peek = function() {
if (_offset >= _tokens.length) {
throw new Error("out-of-bounds");
}
return _tokens[_offset];
};
this.peekKeyword = function(allowed) {
var top = this.peekType("KEYWORD");
return (top != null && allowed.has(top)) ? top : null;
};
this.peekType = function(type) {
if (this.length === 0) {
return null;
}
var top = this.peek();
return (top.type === type) ? top.text : null;
};
this.pop = function() {
var result = this.peek();
_offset++;
return result;
};
this.toString = function() {
var tokens = [];
for (var i = _offset; i < _tokens.length; i++) {
var token = _tokens[i];
tokens.push(token.type + ":" + token.text);
}
return "<TokenString " + tokens.join(" ") + ">";
};
}
function Fragment(guard, type, inputs) {
assertPrivate(guard, _guard$2, "Fragment");
inputs = Object.freeze(inputs.slice());
defineProperties(this, {
type: type,
inputs: inputs
});
}
Fragment.from = function(obj) {
if (typeof (obj) === "string") {
// Try parsing JSON...
try {
Fragment.from(JSON.parse(obj));
}
catch (e) { }
// ...otherwise, use the human-readable lexer
return Fragment.from(lex(obj));
}
if (obj instanceof TokenString) {
// Human-readable ABI (already lexed)
var type = obj.peekKeyword(KwTypes);
switch (type) {
case "constructor": return ConstructorFragment.from(obj);
case "error": return ErrorFragment.from(obj);
case "event": return EventFragment.from(obj);
case "fallback":
case "receive":
return FallbackFragment.from(obj);
case "function": return FunctionFragment.from(obj);
case "struct": return StructFragment.from(obj);
}
}
else if (typeof (obj) === "object") {
// JSON ABI
switch (obj.type) {
case "constructor": return ConstructorFragment.from(obj);
case "error": return ErrorFragment.from(obj);
case "event": return EventFragment.from(obj);
case "fallback":
case "receive":
return FallbackFragment.from(obj);
case "function": return FunctionFragment.from(obj);
case "struct": return StructFragment.from(obj);
}
assert(false, "unsupported type: " + obj.type, "UNSUPPORTED_OPERATION", {
operation: "Fragment.from"
});
}
assertArgument(false, "unsupported frgament object", "obj", obj);
};
Fragment.isConstructor = function(value) {
return ConstructorFragment.isFragment(value);
};
Fragment.isError = function(value) {
return ErrorFragment.isFragment(value);
};
Fragment.isEvent = function(value) {
return EventFragment.isFragment(value);
};
Fragment.isFunction = function(value) {
return FunctionFragment.isFragment(value);
};
Fragment.isStruct = function(value) {
return StructFragment.isFragment(value);
};
/**
* An abstract class to represent An individual fragment
* which has a name from a parse ABI.
*/
function NamedFragment(guard, type, name, inputs) {
Fragment.call(this, guard, type, inputs);
assertArgument(typeof (name) === "string" && name.match(regexId), "invalid identifier", "name", name);
inputs = Object.freeze(inputs.slice());
defineProperties(this, { name: name });
}
NamedFragment.prototype = Object.create(Fragment.prototype);
NamedFragment.prototype.constructor = NamedFragment;
function joinParams(format, params) {
return "(" + params.map((p) => p.format(format)).join((format === "full") ? ", " : ",") + ")";
}
/**
* A Fragment which represents a //Custom Error//.
*/
function ErrorFragment(guard, name, inputs) {
NamedFragment.call(this, guard, "error", name, inputs);
Object.defineProperty(this, internal, { value: ErrorFragmentInternal });
}
ErrorFragment.prototype = Object.create(NamedFragment.prototype);
ErrorFragment.prototype.constructor = ErrorFragment;
Object.defineProperty(ErrorFragment.prototype, "selector", {
get: function() {
return id(this.format("sighash")).substring(0, 10);
},
enumerable: true
});
ErrorFragment.prototype.format = function(format) {
if (format == null) {
format = "sighash";
}
if (format === "json") {
return JSON.stringify({
type: "error",
name: this.name,
inputs: this.inputs.map(function(input) {
return JSON.parse(input.format(format));
})
});
}
var result = [];
if (format !== "sighash") {
result.push("error");
}
result.push(this.name + joinParams(format, this.inputs));
return result.join(" ");
};
ErrorFragment.from = function(obj) {
if (ErrorFragment.isFragment(obj)) {
return obj;
}
if (typeof (obj) === "string") {
return ErrorFragment.from(lex(obj));
}
else if (obj instanceof TokenString) {
var name = consumeName("error", obj);
var inputs = consumeParams(obj);
consumeEoi(obj);
return new ErrorFragment(_guard$2, name, inputs);
}
return new ErrorFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
};
ErrorFragment.isFragment = function(value) {
return (value && value[internal] === ErrorFragmentInternal);
};
/**
* A Fragment which represents an Event.
*/
function EventFragment() {
NamedFragment.apply(this, [arguments[0], "event", arguments[1], arguments[2]]);
}
inherits(EventFragment, NamedFragment);
Object.defineProperty(EventFragment.prototype, "anonymous", {
enumerable: true
});
Object.defineProperty(EventFragment.prototype, "topicHash", {
get: function() {
return id(this.format("sighash"));
},
enumerable: true
});
EventFragment.prototype.format = function(format) {
if (format == null) {
format = "sighash";
}
if (format === "json") {
return JSON.stringify({
type: "event",
anonymous: this.anonymous,
name: this.name,
inputs: this.inputs.map(function(i) {
return JSON.parse(i.format(format));
})
});
}
var result = [];
if (format !== "sighash") {
result.push("event");
}
result.push(this.name + joinParams(format, this.inputs));
if (format !== "sighash" && this.anonymous) {
result.push("anonymous");
}
return result.join(" ");
};
EventFragment.getTopicHash = function(name, params) {
params = (params || []).map(function(p) {
return ParamType.from(p);
});
var fragment = new EventFragment(_guard$2, name, params, false);
return fragment.topicHash;
};
EventFragment.from = function(obj) {
if (EventFragment.isFragment(obj)) {
return obj;
}
if (typeof (obj) === "string") {
try {
return EventFragment.from(lex(obj));
}
catch (error) {
assertArgument(false, "invalid event fragment", "obj", obj);
}
}
else if (obj instanceof TokenString) {
var name = consumeName("event", obj);
var inputs = consumeParams(obj, true);
var anonymous = !!consumeKeywords(obj, setify(["anonymous"])).has("anonymous");
consumeEoi(obj);
return new EventFragment(_guard$2, name, inputs, anonymous);
}
return new EventFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map(function(p) {
return ParamType.from(p, true);
}) : [], !!obj.anonymous);
};
EventFragment.isFragment = function(value) {
return (value && value[internal] === EventFragmentInternal);
};
/**
* A Fragment which represents a constructor.
*/
function ConstructorFragment() {
Fragment.apply(this, arguments);
Object.defineProperty(this, internal, { value: ConstructorFragmentInternal });
defineProperties(this, {
payable: arguments[3],
gas: arguments[4]
});
}
ConstructorFragment.prototype = Object.create(Fragment.prototype);
ConstructorFragment.prototype.constructor = ConstructorFragment;
ConstructorFragment.prototype.format = function(format) {
assert(format != null && format !== "sighash", "cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", { operation: "format(sighash)" });
if (format === "json") {
return JSON.stringify({
type: "constructor",
stateMutability: (this.payable ? "payable" : "undefined"),
payable: this.payable,
gas: ((this.gas != null) ? this.gas : undefined),
inputs: this.inputs.map(function(i) {
return JSON.parse(i.format(format));
})
});
}
var result = ["constructor" + joinParams(format, this.inputs)];
if (this.payable) {
result.push("payable");
}
if (this.gas != null) {
result.push("@" + this.gas.toString());
}
return result.join(" ");
};
ConstructorFragment.from = function(obj) {
if (ConstructorFragment.isFragment(obj)) {
return obj;
}
if (typeof (obj) === "string") {
try {
return ConstructorFragment.from(lex(obj));
}
catch (error) {
assertArgument(false, "invalid constuctor fragment", "obj", obj);
}
}
else if (obj instanceof TokenString) {
consumeKeywords(obj, setify(["constructor"]));
var inputs = consumeParams(obj);
var payable = !!consumeKeywords(obj, KwVisibDeploy).has("payable");
var gas = consumeGas(obj);
consumeEoi(obj);
return new ConstructorFragment(_guard$2, "constructor", inputs, payable, gas);
}
return new ConstructorFragment(_guard$2, "constructor",
obj.inputs ? obj.inputs.map(ParamType.from) : [],
!!obj.payable,
(obj.gas != null) ? obj.gas : null
);
};
ConstructorFragment.isFragment = function(value) {
return (value && value[internal] === ConstructorFragmentInternal);
};
/**
* A Fragment which represents a method.
*/
function FallbackFragment(guard, inputs, payable) {
Fragment.call(this, guard, "fallback", inputs);
Object.defineProperty(this, internal, { value: FallbackFragmentInternal });
defineProperties(this, { payable: payable });
}
FallbackFragment.prototype = Object.create(Fragment.prototype);
FallbackFragment.prototype.constructor = FallbackFragment;
FallbackFragment.prototype.format = function(format) {
var type = ((this.inputs.length === 0) ? "receive" : "fallback");
if (format === "json") {
var stateMutability = (this.payable ? "payable" : "nonpayable");
return JSON.stringify({ type: type, stateMutability: stateMutability });
}
return type + "()" + (this.payable ? " payable" : "");
};
FallbackFragment.from = function(obj) {
if (FallbackFragment.isFragment(obj)) {
return obj;
}
if (typeof (obj) === "string") {
try {
return FallbackFragment.from(lex(obj));
}
catch (error) {
assertArgument(false, "invalid fallback fragment", "obj", obj);
}
}
else if (obj instanceof TokenString) {
var errorObj = obj.toString();
var topIsValid = obj.peekKeyword(setify(["fallback", "receive"]));
assertArgument(topIsValid, "type must be fallback or receive", "obj", errorObj);
var type = obj.popKeyword(setify(["fallback", "receive"]));
// receive()
if (type === "receive") {
var inputs = consumeParams(obj);
assertArgument(inputs.length === 0, "receive cannot have arguments", "obj.inputs", inputs);
consumeKeywords(obj, setify(["payable"]));
consumeEoi(obj);
return new FallbackFragment(_guard$2, [], true);
}
// fallback() [payable]
// fallback(bytes) [payable] returns (bytes)
var inputs = consumeParams(obj);
if (inputs.length) {
assertArgument(inputs.length === 1 && inputs[0].type === "bytes", "invalid fallback inputs", "obj.inputs", inputs.map(function(i) { return i.format("minimal"); }).join(", "));
}
else {
inputs = [ParamType.from("bytes")];
}
var mutability = consumeMutability(obj);
assertArgument(mutability === "nonpayable" || mutability === "payable", "fallback cannot be constants", "obj.stateMutability", mutability);
if (consumeKeywords(obj, setify(["returns"])).has("returns")) {
var outputs = consumeParams(obj);
assertArgument(outputs.length === 1 && outputs[0].type === "bytes", "invalid fallback outputs", "obj.outputs", outputs.map(function(i) { return i.format("minimal"); }).join(", "));
}
consumeEoi(obj);
return new FallbackFragment(_guard$2, inputs, mutability === "payable");
}
if (obj.type === "receive") {
return new FallbackFragment(_guard$2, [], true);
}
if (obj.type === "fallback") {
var inputs = [ParamType.from("bytes")];
var payable = (obj.stateMutability === "payable");
return new FallbackFragment(_guard$2, inputs, payable);
}
assertArgument(false, "invalid fallback description", "obj", obj);
};
FallbackFragment.isFragment = function(value) {
return (value && value[internal] === FallbackFragmentInternal);
};
/**
* A Fragment which represents a method.
*/
function FunctionFragment() {
var guard = arguments[0];
var name = arguments[1];
var stateMutability = arguments[2];
var inputs = arguments[3];
var outputs = arguments[4];
var gas = arguments[5];
NamedFragment.apply(this, [guard, 'function', name, inputs]);
Object.defineProperty(this, internal, { value: FunctionFragmentInternal });
outputs = Object.freeze(outputs.slice());
var constant = (stateMutability === "view" || stateMutability === "pure");
var payable = (stateMutability === "payable");
defineProperties(this, {
constant: constant,
gas: gas,
outputs: outputs,
payable: payable,
stateMutability: stateMutability
});
}
FunctionFragment.prototype = Object.create(NamedFragment.prototype);
FunctionFragment.prototype.constructor = FunctionFragment;
Object.defineProperty(FunctionFragment.prototype, "selector", {
get: function() {
return id(this.format("sighash")).substring(0, 10);
}
});
FunctionFragment.prototype.format = function(format) {
if (format == null) {
format = "sighash";
}
if (format === "json") {
return JSON.stringify({
type: "function",
name: this.name,
constant: this.constant,
stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined),
payable: this.payable,
gas: ((this.gas != null) ? this.gas : undefined),
inputs: this.inputs.map(function(i) { return JSON.parse(i.format(format)); }),
outputs: this.outputs.map(function(o) { return JSON.parse(o.format(format)); })
});
}
var result = [];
if (format !== "sighash") {
result.push("function");
}
result.push(this.name + joinParams(format, this.inputs));
if (format !== "sighash") {
if (this.stateMutability !== "nonpayable") {
result.push(this.stateMutability);
}
if (this.outputs && this.outputs.length) {
result.push("returns");
result.push(joinParams(format, this.outputs));
}
if (this.gas != null) {
result.push("@" + this.gas.toString());
}
}
return result.join(" ");
};
FunctionFragment.getSelector = function(name, params) {
params = (params || []).map(function(p) { return ParamType.from(p); });
var fragment = new FunctionFragment(_guard$2, name, "view", params, [], null);
return fragment.selector;
};
FunctionFragment.from = function(obj) {
if (FunctionFragment.isFragment(obj)) {
return obj;
}
if (typeof (obj) === "string") {
try {
return FunctionFragment.from(lex(obj));
}
catch (error) {
assertArgument(false, "invalid function fragment", "obj", obj);
}
}
else if (obj instanceof TokenString) {
var name = consumeName("function", obj);
var inputs = consumeParams(obj);
var mutability = consumeMutability(obj);
var outputs = [];
if (consumeKeywords(obj, setify(["returns"])).has("returns")) {
outputs = consumeParams(obj);
}
var gas = consumeGas(obj);
consumeEoi(obj);
return new FunctionFragment(_guard$2, name, mutability, inputs, outputs, gas);
}
var stateMutability = obj.stateMutability;
if (stateMutability == null) {
stateMutability = "payable";
if (typeof (obj.constant) === "boolean") {
stateMutability = "view";
if (!obj.constant) {
stateMutability = "payable";
if (typeof (obj.payable) === "boolean" && !obj.payable) {
stateMutability = "nonpayable";
}
}
}
else if (typeof (obj.payable) === "boolean" && !obj.payable) {
stateMutability = "nonpayable";
}
}
return new FunctionFragment(_guard$2, obj.name, stateMutability,
obj.inputs ? obj.inputs.map(ParamType.from) : [],
obj.outputs ? obj.outputs.map(ParamType.from) : [],
(obj.gas != null) ? obj.gas : null);
};
FunctionFragment.isFragment = function(value) {
return (value && value[internal] === FunctionFragmentInternal);
};
/**
* A Fragment which represents a structure.
*/
function StructFragment(guard, name, inputs) {
NamedFragment.call(this, guard, "struct", name, inputs);
Object.defineProperty(this, internal, { value: StructFragmentInternal });
}
StructFragment.prototype = Object.create(NamedFragment.prototype);
StructFragment.prototype.constructor = StructFragment;
/**
* Returns a string representation of this struct as %%format%%.
*/
StructFragment.prototype.format = function() {
throw new Error("@TODO");
};
/**
* Returns a new **StructFragment** for %%obj%%.
*/
StructFragment.from = function(obj) {
if (typeof (obj) === "string") {
try {
return StructFragment.from(lex(obj));
}
catch (error) {
assertArgument(false, "invalid struct fragment", "obj", obj);
}
}
else if (obj instanceof TokenString) {
var name = consumeName("struct", obj);
var inputs = consumeParams(obj);
consumeEoi(obj);
return new StructFragment(_guard$2, name, inputs);
}
return new StructFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
};
// @TODO: fix this return type
/**
* Returns ``true`` and provides a type guard if %%value%% is a
* **StructFragment**.
*/
StructFragment.isFragment = function(value) {
return (value && value[internal] === StructFragmentInternal);
};
/**
* When sending values to or receiving values from a [[Contract]], the
* data is generally encoded using the [ABI standard](link-solc-abi).
*
* The AbiCoder provides a utility to encode values to ABI data and
* decode values from ABI data.
*
* Most of the time, developers should favour the [[Contract]] class,
* which further abstracts a lot of the finer details of ABI data.
*
* @_section api/abi/abi-coder:ABI Encoding
*/
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
// https://docs.soliditylang.org/en/v0.8.17/control-structures.html
const PanicReasons$1 = new Map();
PanicReasons$1.set(0x00, "GENERIC_PANIC");
PanicReasons$1.set(0x01, "ASSERT_FALSE");
PanicReasons$1.set(0x11, "OVERFLOW");
PanicReasons$1.set(0x12, "DIVIDE_BY_ZERO");
PanicReasons$1.set(0x21, "ENUM_RANGE_ERROR");
PanicReasons$1.set(0x22, "BAD_STORAGE_DATA");
PanicReasons$1.set(0x31, "STACK_UNDERFLOW");
PanicReasons$1.set(0x32, "ARRAY_RANGE_ERROR");
PanicReasons$1.set(0x41, "OUT_OF_MEMORY");
PanicReasons$1.set(0x51, "UNINITIALIZED_FUNCTION_CALL");
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
let defaultCoder = null;
let defaultMaxInflation = 1024;
function getBuiltinCallException(action, tx, data, abiCoder) {
var message = "missing revert data";
var reason = null;
var invocation = null;
var revert = null;
if (data) {
message = "execution reverted";
var bytes = getBytes(data);
data = hexlify(data);
if (bytes.length === 0) {
message += " (no data present; likely require(false) occurred";
reason = "require(false)";
}
else if (bytes.length % 32 !== 4) {
message += " (could not decode reason; invalid data length)";
}
else if (hexlify(bytes.slice(0, 4)) === "0x08c379a0") {
// Error(string)
try {
reason = abiCoder.decode(["string"], bytes.slice(4))[0];
revert = {
signature: "Error(string)",
name: "Error",
args: [reason]
};
message += ": " + JSON.stringify(reason);
}
catch (error) {
message += " (could not decode reason; invalid string data)";
}
}
else if (hexlify(bytes.slice(0, 4)) === "0x4e487b71") {
// Panic(uint256)
try {
var code = Number(abiCoder.decode(["uint256"], bytes.slice(4))[0]);
revert = {
signature: "Panic(uint256)",
name: "Panic",
args: [code]
};
reason = "Panic due to " + (PanicReasons$1.get(code) || "UNKNOWN") + "(" + code + ")";
message += ": " + reason;
}
catch (error) {
message += " (could not decode panic code)";
}
}
else {
message += " (unknown custom error)";
}
}
var transaction = {
to: (tx.to ? getAddress(tx.to) : null),
data: (tx.data || "0x")
};
if (tx.from) {
transaction.from = getAddress(tx.from);
}
return makeError(message, "CALL_EXCEPTION", {
action: action,
data: data,
reason: reason,
transaction: transaction,
invocation: invocation,
revert: revert
});
}
function Coder(name, type, localName, dynamic) {
// The coder name:
// - address, uint256, tuple, array, etc.
this.name = void 0;
// The fully expanded type, including composite types:
// - address, uint256, tuple(address,bytes), uint256[3][4][], etc.
this.type = void 0;
// The localName bound in the signature, in this example it is "baz":
// - tuple(address foo, uint bar) baz
this.localName = void 0;
// Whether this type is dynamic:
// - Dynamic: bytes, string, address[], tuple(boolean[]), etc.
// - Not Dynamic: address, uint256, boolean[3], tuple(address, uint8)
this.dynamic = void 0;
defineProperties(this, {
name: name,
type: type,
localName: localName,
dynamic: dynamic
}, {
name: "string",
type: "string",
localName: "string",
dynamic: "boolean"
});
}
Coder.prototype._throwError = function(message, value) {
assertArgument(false, message, this.localName, value);
};
function getNumber(value, name) {
if(value instanceof BigInteger) {
return value;
}
switch (typeof (value)) {
case "bigint":
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return Number(value);
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return value;
case "string":
try {
if (value === "") {
throw new Error("empty string");
}
return getNumber(BigInt(value), name);
}
catch (e) {
assertArgument(false, `invalid numeric string: ${e.message}`, name || "value", value);
}
}
assertArgument(false, "invalid numeric value", name || "value", value);
}
function fromTwos(_value, _width) {
const value = getUint(_value, "value");
const width = BigInt(getNumber(_width, "width"));
// 使用BigInteger的shiftRight替代>>
assert(value.shiftRight(width).equals(BN_0$a), "overflow", "NUMERIC_FAULT", {
operation: "fromTwos", fault: "overflow", value: _value
});
// 使用BigInteger的shiftRight和subtract替代>>和-
if (value.shiftRight(width.subtract(BN_1$5)).equals(BN_0$a) === false) {
// 使用BigInteger的shiftLeft、subtract、not、and和add替代<<、-、~、&和+
const mask = BN_1$5.shiftLeft(width).subtract(BN_1$5);
return value.not().and(mask).add(BN_1$5).negate();
}
return value;
}
function toTwos(_value, _width) {
let value = getBigInt(_value, "value");
const width = BigInt(getNumber(_width, "width"));
// 使用BigInteger的shiftLeft和subtract替代<<和-
const limit = BN_1$5.shiftLeft(width.subtract(BN_1$5));
if (value.compareTo(BN_0$a) < 0) {
value = value.negate();
assert(value.compareTo(limit) <= 0, "too low", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
// 使用BigInteger的shiftLeft、subtract替代<<和-
const mask = BN_1$5.shiftLeft(width).subtract(BN_1$5);
// 使用BigInteger的not、and和add替代~、&和+
return value.not().and(mask).add(BN_1$5);
} else {
assert(value.compareTo(limit) < 0, "too high", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
}
return value;
}
function mask(_value, _bits) {
const value = getUint(_value, "value");
const bits = BigInt(getNumber(_bits, "bits"));
const mask = BN_1$5.shiftLeft(bits).subtract(BN_1$5);
return value.and(mask);
}
function Writer() {
var _data = [];
var _dataLength = 0;
function _writeData(data) {
_data.push(data);
_dataLength += data.length;
return data.length;
}
Object.defineProperty(this, "data", {
get: function() {
return concat(_data);
}
});
Object.defineProperty(this, "length", {
get: function() {
return _dataLength;
}
});
this.appendWriter = function(writer) {
return _writeData(getBytesCopy(writer.data));
};
this.writeBytes = function(value) {
var bytes = getBytesCopy(value);
var paddingOffset = bytes.length % WordSize;
if (paddingOffset) {
bytes = getBytesCopy(concat([bytes, Padding.slice(paddingOffset)]));
}
return _writeData(bytes);
};
this.writeValue = function(value) {
return _writeData(getValue$1(value));
};
this.writeUpdatableValue = function() {
var offset = _data.length;
_data.push(Padding);
_dataLength += WordSize;
return function(value) {
_data[offset] = getValue$1(value);
};
};
}
/**
* @_ignore
*/
function Reader(data, allowLoose, maxInflation) {
var _this = this;
var _data;
var _offset;
var _bytesRead;
var _parent;
var _maxInflation;
defineProperties(this, { allowLoose: !!allowLoose });
_data = getBytesCopy(data);
_bytesRead = 0;
_parent = null;
_maxInflation = (maxInflation != null) ? maxInflation : 1024;
_offset = 0;
function _incrementBytesRead(count) {
if (_parent) {
return _parent._incrementBytesRead(count);
}
_bytesRead += count;
// Check for excessive inflation (see: #4537)
assert(_maxInflation < 1 || _bytesRead <= _maxInflation * _this.dataLength, `compressed ABI data exceeds inflation ratio of ${_maxInflation} ( see: https:/\/github.com/ethers-io/ethers.js/issues/4537 )`, "BUFFER_OVERRUN", {
buffer: getBytesCopy(_data), offset: _offset,
length: count, info: {
bytesRead: _bytesRead,
dataLength: _this.dataLength
}
});
}
function _peekBytes(offset, length, loose) {
var alignedLength = Math.ceil(length / WordSize) * WordSize;
if (_offset + alignedLength > _data.length) {
if (_this.allowLoose && loose && _offset + length <= _data.length) {
alignedLength = length;
}
else {
assert(false, "data out-of-bounds", "BUFFER_OVERRUN", {
buffer: getBytesCopy(_data),
length: _data.length,
offset: _offset + alignedLength
});
}
}
return _data.slice(_offset, _offset + alignedLength);
}
Object.defineProperty(this, "data", {
get: function() { return hexlify(_data); }
});
Object.defineProperty(this, "dataLength", {
get: function() { return _data.length; }
});
Object.defineProperty(this, "consumed", {
get: function() { return _offset; }
});
Object.defineProperty(this, "bytes", {
get: function() { return new Uint8Array(_data); }
});
// Create a sub-reader with the same underlying data, but offset
this.subReader = function(offset) {
var reader = new Reader(_data.slice(_offset + offset), _this.allowLoose, _maxInflation);
reader._parent = _this;
return reader;
};
// Read bytes
this.readBytes = function(length, loose) {
var bytes = _peekBytes(0, length, !!loose);
_incrementBytesRead(length);
_offset += bytes.length;
// @TODO: Make sure the length..end bytes are all 0?
return bytes.slice(0, length);
};
// Read a numeric values
this.readValue = function() {
return toBigInt(_this.readBytes(WordSize));
};
this.readIndex = function() {
return toNumber(_this.readBytes(WordSize));
};
}
function AnonymousCoder(coder) {
Coder.call(this, coder.name, coder.type, "_", coder.dynamic);
this.coder = coder;
}
AnonymousCoder.prototype = Object.create(Coder.prototype);
AnonymousCoder.prototype.constructor = AnonymousCoder;
AnonymousCoder.prototype.defaultValue = function() {
return this.coder.defaultValue();
};
AnonymousCoder.prototype.encode = function(writer, value) {
return this.coder.encode(writer, value);
};
AnonymousCoder.prototype.decode = function(reader) {
return this.coder.decode(reader);
};
/**
* @_ignore
*/
function pack(writer, coders, values) {
let arrayValues = [];
if (Array.isArray(values)) {
arrayValues = values;
}
else if (values && typeof (values) === "object") {
let unique = {};
arrayValues = coders.map((coder) => {
const name = coder.localName;
assert(name,
"cannot encode object for signature with missing names", "INVALID_ARGUMENT",
{ argument: "values", info: { coder: coder }, value: values }
);
assert(!unique[name],
"cannot encode object for signature with duplicate names", "INVALID_ARGUMENT",
{ argument: "values", info: { coder: coder }, value: values });
unique[name] = true;
return values[name];
});
}
else {
assertArgument(false, "invalid tuple value", "tuple", values);
}
assertArgument(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values);
let staticWriter = new Writer();
let dynamicWriter = new Writer();
let updateFuncs = [];
coders.forEach((coder, index) => {
let value = arrayValues[index];
if (coder.dynamic) {
// Get current dynamic offset (for the future pointer)
let dynamicOffset = dynamicWriter.length;
// Encode the dynamic value into the dynamicWriter
coder.encode(dynamicWriter, value);
// Prepare to populate the correct offset once we are done
let updateFunc = staticWriter.writeUpdatableValue();
updateFuncs.push((baseOffset) => {
updateFunc(baseOffset + dynamicOffset);
});
}
else {
coder.encode(staticWriter, value);
}
});
// Backfill all the dynamic offsets, now that we know the static length
updateFuncs.forEach((func) => { func(staticWriter.length); });
let length = writer.appendWriter(staticWriter);
length += writer.appendWriter(dynamicWriter);
return length;
}
/**
* @_ignore
*/
function unpack(reader, coders) {
let values = [];
let keys = [];
// A reader anchored to this base
let baseReader = reader.subReader(0);
coders.forEach((coder) => {
let value = null;
if (coder.dynamic) {
let offset = reader.readIndex();
let offsetReader = baseReader.subReader(offset);
try {
value = coder.decode(offsetReader);
}
catch (error) {
// Cannot recover from this
if (isError(error, "BUFFER_OVERRUN")) {
throw error;
}
value = error;
value.baseType = coder.name;
value.name = coder.localName;
value.type = coder.type;
}
}
else {
try {
value = coder.decode(reader);
}
catch (error) {
// Cannot recover from this
if (isError(error, "BUFFER_OVERRUN")) {
throw error;
}
value = error;
value.baseType = coder.name;
value.name = coder.localName;
value.type = coder.type;
}
}
if (value == undefined) {
throw new Error("investigate");
}
values.push(value);
keys.push(coder.localName || null);
});
return values;
}
/**
* @_ignore
*/
function ArrayCoder(coder, length, localName) {
var type = (coder.type + "[" + (length >= 0 ? length : "") + "]");
var dynamic = (length === -1 || coder.dynamic);
Coder.call(this, "array", type, localName, dynamic);
defineProperties(this, { coder: coder, length: length });
}
inherits(ArrayCoder, Coder);
ArrayCoder.prototype.defaultValue = function() {
// Verifies the child coder is valid (even if the array is dynamic or 0-length)
var defaultChild = this.coder.defaultValue();
var result = [];
for (var i = 0; i < this.length; i++) {
result.push(defaultChild);
}
return result;
};
ArrayCoder.prototype.encode = function(writer, _value) {
var value = Typed.dereference(_value, "array");
if (!Array.isArray(value)) {
this._throwError("expected array value", value);
}
var count = this.length;
if (count === -1) {
count = value.length;
writer.writeValue(value.length);
}
assertArgumentCount(value.length, count, "coder array" + (this.localName ? (" " + this.localName) : ""));
var coders = [];
for (var i = 0; i < value.length; i++) {
coders.push(this.coder);
}
return pack(writer, coders, value);
};
ArrayCoder.prototype.decode = function(reader) {
var count = this.length;
if (count === -1) {
count = reader.readIndex();
// Check that there is *roughly* enough data to ensure
// stray random data is not being read as a length. Each
// slot requires at least 32 bytes for their value (or 32
// bytes as a link to the data). This could use a much
// tighter bound, but we are erroring on the side of safety.
assert(count * WordSize <= reader.dataLength, "insufficient data length", "BUFFER_OVERRUN", { buffer: reader.bytes, offset: count * WordSize, length: reader.dataLength });
}
var coders = [];
for (var i = 0; i < count; i++) {
coders.push(new AnonymousCoder(this.coder));
}
return unpack(reader, coders);
};
/**
* @_ignore
*/
function BooleanCoder(localName) {
Coder.call(this, "bool", "bool", localName, false);
}
BooleanCoder.prototype = Object.create(Coder.prototype);
BooleanCoder.prototype.constructor = BooleanCoder;
BooleanCoder.prototype.defaultValue = function() {
return false;
};
BooleanCoder.prototype.encode = function(writer, _value) {
var value = Typed.dereference(_value, "bool");
return writer.writeValue(value ? 1 : 0);
};
BooleanCoder.prototype.decode = function(reader) {
return !!reader.readValue();
};
/**
* @_ignore
*/
function DynamicBytesCoder(type, localName) {
Coder.call(this, type, type, localName, true);
}
DynamicBytesCoder.prototype = Object.create(Coder.prototype);
DynamicBytesCoder.prototype.constructor = DynamicBytesCoder;
DynamicBytesCoder.prototype.defaultValue = function() {
return "0x";
};
DynamicBytesCoder.prototype.encode = function(writer, value) {
value = getBytesCopy(value);
var length = writer.writeValue(value.length);
length += writer.writeBytes(value);
return length;
};
DynamicBytesCoder.prototype.decode = function(reader) {
return reader.readBytes(reader.readIndex(), true);
};
/**
* @_ignore
*/
function BytesCoder(localName) {
DynamicBytesCoder.call(this, "bytes", localName);
}
BytesCoder.prototype = Object.create(DynamicBytesCoder.prototype);
BytesCoder.prototype.constructor = BytesCoder;
BytesCoder.prototype.decode = function(reader) {
return hexlify(DynamicBytesCoder.prototype.decode.call(this, reader));
};
/**
* @_ignore
*/
function FixedBytesCoder(size, localName) {
var name = "bytes" + String(size);
Coder.call(this, name, name, localName, false);
defineProperties(this, { size: size }, { size: "number" });
}
FixedBytesCoder.prototype = Object.create(Coder.prototype);
FixedBytesCoder.prototype.constructor = FixedBytesCoder;
FixedBytesCoder.prototype.defaultValue = function() {
return ("0x0000000000000000000000000000000000000000000000000000000000000000").substring(0, 2 + this.size * 2);
};
FixedBytesCoder.prototype.encode = function(writer, _value) {
var data = getBytesCopy(Typed.dereference(_value, this.type));
if (data.length !== this.size) {
this._throwError("incorrect data length", _value);
}
return writer.writeBytes(data);
};
FixedBytesCoder.prototype.decode = function(reader) {
return hexlify(reader.readBytes(this.size));
};
const Empty = new Uint8Array([]);
/**
* @_ignore
*/
function NullCoder(localName) {
Coder.call(this, "null", "", localName, false);
}
NullCoder.prototype = Object.create(Coder.prototype);
NullCoder.prototype.constructor = NullCoder;
NullCoder.prototype.defaultValue = function() {
return null;
};
NullCoder.prototype.encode = function(writer, value) {
if (value != null) {
this._throwError("not null", value);
}
return writer.writeBytes(Empty);
};
NullCoder.prototype.decode = function(reader) {
reader.readBytes(0);
return null;
};
const BN_0$5 = BigInt(0);
const BN_1$2 = BigInt(1);
const BN_MAX_UINT256$1 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
/**
* @_ignore
*/
function NumberCoder(size, signed, localName) {
var name = ((signed ? "int" : "uint") + (size * 8));
Coder.call(this, name, name, localName, false);
defineProperties(this, { size: size, signed: signed }, { size: "number", signed: "boolean" });
}
NumberCoder.prototype = Object.create(Coder.prototype);
NumberCoder.prototype.constructor = NumberCoder;
NumberCoder.prototype.defaultValue = function() {
return 0;
};
NumberCoder.prototype.encode = function(writer, _value) {
var value = getBigInt(Typed.dereference(_value, this.type));
// Check bounds are safe for encoding
var maxUintValue = mask(BN_MAX_UINT256$1, WordSize * 8);
if (this.signed) {
var bounds = mask(maxUintValue, (this.size * 8) - 1);
if (value > bounds || value < -(bounds + BN_1$2)) {
this._throwError("value out-of-bounds", _value);
}
value = toTwos(value, 8 * WordSize);
}
else if (value < BN_0$5 || value > mask(maxUintValue, this.size * 8)) {
this._throwError("value out-of-bounds", _value);
}
return writer.writeValue(value);
};
NumberCoder.prototype.decode = function(reader) {
try {
var value = mask(reader.readValue(), this.size * 8);
if (this.signed) {
value = fromTwos(value, this.size * 8);
}
return value;
}
catch(e) {
throw e;
}
};
/**
* @_ignore
*/
function StringCoder(localName) {
DynamicBytesCoder.call(this, "string", localName);
}
StringCoder.prototype = Object.create(DynamicBytesCoder.prototype);
StringCoder.prototype.constructor = StringCoder;
StringCoder.prototype.defaultValue = function() {
return "";
};
StringCoder.prototype.encode = function(writer, _value) {
return DynamicBytesCoder.prototype.encode.call(this, writer, toUtf8Bytes(Typed.dereference(_value, "string")));
};
StringCoder.prototype.decode = function(reader) {
return toUtf8String(DynamicBytesCoder.prototype.decode.call(this, reader));
};
/**
* @_ignore
*/
function TupleCoder(coders, localName) {
var dynamic = false;
var types = [];
coders.forEach(function(coder) {
if (coder.dynamic) {
dynamic = true;
}
types.push(coder.type);
});
var type = ("tuple(" + types.join(",") + ")");
Coder.call(this, "tuple", type, localName, dynamic);
defineProperties(this, { coders: Object.freeze(coders.slice()) });
}
TupleCoder.prototype = Object.create(Coder.prototype);
TupleCoder.prototype.constructor = TupleCoder;
TupleCoder.prototype.defaultValue = function() {
var values = [];
var self = this;
this.coders.forEach(function(coder) {
values.push(coder.defaultValue());
});
// We only output named properties for uniquely named coders
var uniqueNames = this.coders.reduce(function(accum, coder) {
var name = coder.localName;
if (name) {
if (!accum[name]) {
accum[name] = 0;
}
accum[name]++;
}
return accum;
}, {});
// Add named values
this.coders.forEach(function(coder, index) {
var name = coder.localName;
if (!name || uniqueNames[name] !== 1) {
return;
}
if (name === "length") {
name = "_length";
}
if (values[name] != null) {
return;
}
values[name] = values[index];
});
return Object.freeze(values);
};
TupleCoder.prototype.encode = function(writer, _value) {
var value = Typed.dereference(_value, "tuple");
return pack(writer, this.coders, value);
};
TupleCoder.prototype.decode = function(reader) {
return unpack(reader, this.coders);
};
function AddressCoder(localName) {
Coder.call(this, "address", "address", localName, false);
}
AddressCoder.prototype = Object.create(Coder.prototype);
AddressCoder.prototype.constructor = AddressCoder;
AddressCoder.prototype.defaultValue = function() {
return "0x0000000000000000000000000000000000000000";
};
AddressCoder.prototype.encode = function(writer, _value) {
var value = Typed.dereference(_value, "string");
try {
value = getAddress(value);
}
catch (error) {
return this._throwError(error.message, _value);
}
return writer.writeValue(value);
};
AddressCoder.prototype.decode = function(reader) {
return getAddress(toBeHex(reader.readValue(), 20));
};
/**
* The **AbiCoder** is a low-level class responsible for encoding JavaScript
* values into binary data and decoding binary data into JavaScript values.
*/
function AbiCoder() {
var self = this;
function getCoder(param) {
if (param.isArray()) {
return new ArrayCoder(getCoder(param.arrayChildren), param.arrayLength, param.name);
}
if (param.isTuple()) {
return new TupleCoder(param.components.map(function(c) {
return getCoder(c);
}), param.name);
}
switch (param.baseType) {
case "address":
return new AddressCoder(param.name);
case "bool":
return new BooleanCoder(param.name);
case "string":
return new StringCoder(param.name);
case "bytes":
return new BytesCoder(param.name);
case "":
return new NullCoder(param.name);
}
// u?int[0-9]*
var match = param.type.match(paramTypeNumber);
if (match) {
var size = parseInt(match[2] || "256");
assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid " + match[1] + " bit length", "param", param);
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
}
// bytes[0-9]+
match = param.type.match(paramTypeBytes);
if (match) {
var size = parseInt(match[1]);
assertArgument(size !== 0 && size <= 32, "invalid bytes length", "param", param);
return new FixedBytesCoder(size, param.name);
}
assertArgument(false, "invalid type", "type", param.type);
}
this.getDefaultValue = function(types) {
var coders = types.map(function(type) {
return getCoder(ParamType.from(type));
});
var coder = new TupleCoder(coders, "_");
return coder.defaultValue();
};
this.encode = function(types, values) {
assertArgumentCount(values.length, types.length, "types/values length mismatch");
var coders = types.map(function(type) {
return getCoder(ParamType.from(type));
});
var coder = (new TupleCoder(coders, "_"));
var writer = new Writer();
coder.encode(writer, values);
return writer.data;
};
this.decode = function(types, data, loose) {
var coders = types.map(function(type) {
return getCoder(ParamType.from(type));
});
var coder = new TupleCoder(coders, "_");
return coder.decode(new Reader(data, loose, defaultMaxInflation));
};
}
AbiCoder._setDefaultMaxInflation = function(value) {
assertArgument(typeof (value) === "number" && Number.isInteger(value), "invalid defaultMaxInflation factor", "value", value);
defaultMaxInflation = value;
};
AbiCoder.defaultAbiCoder = function() {
if (defaultCoder == null) {
defaultCoder = new AbiCoder();
}
return defaultCoder;
};
AbiCoder.getBuiltinCallException = function(action, tx, data) {
return getBuiltinCallException(action, tx, data, AbiCoder.defaultAbiCoder());
};
/**
* The Interface class is a low-level class that accepts an
* ABI and provides all the necessary functionality to encode
* and decode paramaters to and results from methods, events
* and errors.
*
* It also provides several convenience methods to automatically
* search and find matching transactions and events to parse them.
*
* @_subsection api/abi:Interfaces [interfaces]
*/
/**
* When using the [[Interface-parseLog]] to automatically match a Log to its event
* for parsing, a **LogDescription** is returned.
*/
function LogDescription(fragment, topic, args) {
/**
* The matching fragment for the ``topic0``.
*/
this.fragment = undefined;
/**
* The name of the Event.
*/
this.name = undefined;
/**
* The full Event signature.
*/
this.signature = undefined;
/**
* The topic hash for the Event.
*/
this.topic = undefined;
/**
* The arguments passed into the Event with ``emit``.
*/
this.args = undefined;
var name = fragment.name;
var signature = fragment.format();
defineProperties(this, {
fragment: fragment,
name: name,
signature: signature,
topic: topic,
args: args
});
}
/**
* When using the [[Interface-parseTransaction]] to automatically match
* a transaction data to its function for parsing,
* a **TransactionDescription** is returned.
*/
function TransactionDescription(fragment, selector, args, value) {
/**
* The matching fragment from the transaction ``data``.
*/
this.fragment = undefined;
/**
* The name of the Function from the transaction ``data``.
*/
this.name = undefined;
/**
* The arguments passed to the Function from the transaction ``data``.
*/
this.args = undefined;
/**
* The full Function signature from the transaction ``data``.
*/
this.signature = undefined;
/**
* The selector for the Function from the transaction ``data``.
*/
this.selector = undefined;
/**
* The ``value`` (in wei) from the transaction.
*/
this.value = undefined;
var name = fragment.name;
var signature = fragment.format();
defineProperties(this, {
fragment: fragment,
name: name,
args: args,
signature: signature,
selector: selector,
value: value
});
}
/**
* When using the [[Interface-parseError]] to automatically match an
* error for a call result for parsing, an **ErrorDescription** is returned.
*/
function ErrorDescription(fragment, selector, args) {
/**
* The matching fragment.
*/
this.fragment = undefined;
/**
* The name of the Error.
*/
this.name = undefined;
/**
* The arguments passed to the Error with ``revert``.
*/
this.args = undefined;
/**
* The full Error signature.
*/
this.signature = undefined;
/**
* The selector for the Error.
*/
this.selector = undefined;
var name = fragment.name;
var signature = fragment.format();
defineProperties(this, {
fragment: fragment,
name: name,
args: args,
signature: signature,
selector: selector
});
}
/**
* An **Indexed** is used as a value when a value that does not
* fit within a topic (i.e. not a fixed-length, 32-byte type). It
* is the ``keccak256`` of the value, and used for types such as
* arrays, tuples, bytes and strings.
*/
function Indexed(hash) {
/**
* The ``keccak256`` of the value logged.
*/
this.hash = undefined;
/**
* @_ignore:
*/
this._isIndexed = undefined;
defineProperties(this, {
hash: hash,
_isIndexed: true
});
}
/**
* Returns ``true`` if %%value%% is an **Indexed**.
*
* This provides a Type Guard for property access.
*/
Indexed.isIndexed = function(value) {
return !!(value && value._isIndexed);
};
// https://docs.soliditylang.org/en/v0.8.13/control-structures.html?highlight=panic#panic-via-assert-and-error-via-require
const PanicReasons = {
"0": "generic panic",
"1": "assert(false)",
"17": "arithmetic overflow",
"18": "division or modulo by zero",
"33": "enum overflow",
"34": "invalid encoded storage byte array accessed",
"49": "out-of-bounds array access; popping on an empty array",
"50": "out-of-bounds access of an array or bytesN",
"65": "out of memory",
"81": "uninitialized function",
};
const BuiltinErrors = {
"0x08c379a0": {
signature: "Error(string)",
name: "Error",
inputs: ["string"],
reason: (message) => {
return `reverted with reason string ${JSON.stringify(message)}`;
}
},
"0x4e487b71": {
signature: "Panic(uint256)",
name: "Panic",
inputs: ["uint256"],
reason: (code) => {
let reason = "unknown panic code";
if (code >= 0 && code <= 0xff && PanicReasons[code.toString()]) {
reason = PanicReasons[code.toString()];
}
return `reverted with panic code 0x${code.toString(16)} (${reason})`;
}
}
};
function n(value, width) {
let signed = false;
if (width < 0) {
signed = true;
width *= -1;
}
// @TODO: Check range is valid for value
return new Typed(_gaurd, `${signed ? "" : "u"}int${width}`, value, { signed: signed, width: width });
}
function b(value, size) {
// @TODO: Check range is valid for value
return new Typed(_gaurd, `bytes${(size) ? size : ""}`, value, { size: size });
}
function Typed(gaurd, type, value, options) {
if (!(this instanceof Typed)) {
return new Typed(gaurd, type, value, options);
}
if (options == null) {
options = null;
}
assertPrivate(_gaurd, gaurd, "Typed");
defineProperties(this, { _typedSymbol: _typedSymbol, type: type, value: value });
this._options = options;
// Check the value is valid
this.format();
}
Typed.prototype.format = function() {
if (this.type === "array") {
throw new Error("");
}
else if (this.type === "dynamicArray") {
throw new Error("");
}
else if (this.type === "tuple") {
return "tuple(" + this.value.map(function(v) { return v.format(); }).join(",") + ")";
}
return this.type;
};
Typed.prototype.defaultValue = function() {
return 0;
};
Typed.prototype.minValue = function() {
return 0;
};
Typed.prototype.maxValue = function() {
return 0;
};
Typed.prototype.isBigInt = function() {
return !!(this.type.match(/^u?int[0-9]+$/));
};
Typed.prototype.isData = function() {
return this.type.startsWith("bytes");
};
Typed.prototype.isString = function() {
return (this.type === "string");
};
Typed.prototype.getTupleName = function() {
if (this.type !== "tuple") {
throw TypeError("not a tuple");
}
return this._options;
};
Typed.prototype.getArrayLength = function() {
if (this.type !== "array") {
throw TypeError("not an array");
}
if (this._options === true) {
return -1;
}
if (this._options === false) {
return (this.value).length;
}
return null;
};
Typed.from = function(type, value) {
return new Typed(_gaurd, type, value);
};
Typed.uint8 = function(v) { return n(v, 8); };
Typed.uint16 = function(v) { return n(v, 16); };
Typed.uint24 = function(v) { return n(v, 24); };
Typed.uint32 = function(v) { return n(v, 32); };
Typed.uint40 = function(v) { return n(v, 40); };
Typed.uint48 = function(v) { return n(v, 48); };
Typed.uint56 = function(v) { return n(v, 56); };
Typed.uint64 = function(v) { return n(v, 64); };
Typed.uint72 = function(v) { return n(v, 72); };
Typed.uint80 = function(v) { return n(v, 80); };
Typed.uint88 = function(v) { return n(v, 88); };
Typed.uint96 = function(v) { return n(v, 96); };
Typed.uint104 = function(v) { return n(v, 104); };
Typed.uint112 = function(v) { return n(v, 112); };
Typed.uint120 = function(v) { return n(v, 120); };
Typed.uint128 = function(v) { return n(v, 128); };
Typed.uint136 = function(v) { return n(v, 136); };
Typed.uint144 = function(v) { return n(v, 144); };
Typed.uint152 = function(v) { return n(v, 152); };
Typed.uint160 = function(v) { return n(v, 160); };
Typed.uint168 = function(v) { return n(v, 168); };
Typed.uint176 = function(v) { return n(v, 176); };
Typed.uint184 = function(v) { return n(v, 184); };
Typed.uint192 = function(v) { return n(v, 192); };
Typed.uint200 = function(v) { return n(v, 200); };
Typed.uint208 = function(v) { return n(v, 208); };
Typed.uint216 = function(v) { return n(v, 216); };
Typed.uint224 = function(v) { return n(v, 224); };
Typed.uint232 = function(v) { return n(v, 232); };
Typed.uint240 = function(v) { return n(v, 240); };
Typed.uint248 = function(v) { return n(v, 248); };
Typed.uint256 = function(v) { return n(v, 256); };
Typed.uint = function(v) { return n(v, 256); };
Typed.int8 = function(v) { return n(v, -8); };
Typed.int16 = function(v) { return n(v, -16); };
Typed.int24 = function(v) { return n(v, -24); };
Typed.int32 = function(v) { return n(v, -32); };
Typed.int40 = function(v) { return n(v, -40); };
Typed.int48 = function(v) { return n(v, -48); };
Typed.int56 = function(v) { return n(v, -56); };
Typed.int64 = function(v) { return n(v, -64); };
Typed.int72 = function(v) { return n(v, -72); };
Typed.int80 = function(v) { return n(v, -80); };
Typed.int88 = function(v) { return n(v, -88); };
Typed.int96 = function(v) { return n(v, -96); };
Typed.int104 = function(v) { return n(v, -104); };
Typed.int112 = function(v) { return n(v, -112); };
Typed.int120 = function(v) { return n(v, -120); };
Typed.int128 = function(v) { return n(v, -128); };
Typed.int136 = function(v) { return n(v, -136); };
Typed.int144 = function(v) { return n(v, -144); };
Typed.int152 = function(v) { return n(v, -152); };
Typed.int160 = function(v) { return n(v, -160); };
Typed.int168 = function(v) { return n(v, -168); };
Typed.int176 = function(v) { return n(v, -176); };
Typed.int184 = function(v) { return n(v, -184); };
Typed.int192 = function(v) { return n(v, -192); };
Typed.int200 = function(v) { return n(v, -200); };
Typed.int208 = function(v) { return n(v, -208); };
Typed.int216 = function(v) { return n(v, -216); };
Typed.int224 = function(v) { return n(v, -224); };
Typed.int232 = function(v) { return n(v, -232); };
Typed.int240 = function(v) { return n(v, -240); };
Typed.int248 = function(v) { return n(v, -248); };
Typed.int256 = function(v) { return n(v, -256); };
Typed.int = function(v) { return n(v, -256); };
Typed.bytes1 = function(v) { return b(v, 1); };
Typed.bytes2 = function(v) { return b(v, 2); };
Typed.bytes3 = function(v) { return b(v, 3); };
Typed.bytes4 = function(v) { return b(v, 4); };
Typed.bytes5 = function(v) { return b(v, 5); };
Typed.bytes6 = function(v) { return b(v, 6); };
Typed.bytes7 = function(v) { return b(v, 7); };
Typed.bytes8 = function(v) { return b(v, 8); };
Typed.bytes9 = function(v) { return b(v, 9); };
Typed.bytes10 = function(v) { return b(v, 10); };
Typed.bytes11 = function(v) { return b(v, 11); };
Typed.bytes12 = function(v) { return b(v, 12); };
Typed.bytes13 = function(v) { return b(v, 13); };
Typed.bytes14 = function(v) { return b(v, 14); };
Typed.bytes15 = function(v) { return b(v, 15); };
Typed.bytes16 = function(v) { return b(v, 16); };
Typed.bytes17 = function(v) { return b(v, 17); };
Typed.bytes18 = function(v) { return b(v, 18); };
Typed.bytes19 = function(v) { return b(v, 19); };
Typed.bytes20 = function(v) { return b(v, 20); };
Typed.bytes21 = function(v) { return b(v, 21); };
Typed.bytes22 = function(v) { return b(v, 22); };
Typed.bytes23 = function(v) { return b(v, 23); };
Typed.bytes24 = function(v) { return b(v, 24); };
Typed.bytes25 = function(v) { return b(v, 25); };
Typed.bytes26 = function(v) { return b(v, 26); };
Typed.bytes27 = function(v) { return b(v, 27); };
Typed.bytes28 = function(v) { return b(v, 28); };
Typed.bytes29 = function(v) { return b(v, 29); };
Typed.bytes30 = function(v) { return b(v, 30); };
Typed.bytes31 = function(v) { return b(v, 31); };
Typed.bytes32 = function(v) { return b(v, 32); };
Typed.address = function(v) { return new Typed(_gaurd, "address", v); };
Typed.bool = function(v) { return new Typed(_gaurd, "bool", !!v); };
Typed.bytes = function(v) { return new Typed(_gaurd, "bytes", v); };
Typed.string = function(v) { return new Typed(_gaurd, "string", v); };
Typed.array = function(v, dynamic) {
throw new Error("not implemented yet");
};
Typed.tuple = function(v, name) {
throw new Error("not implemented yet");
};
Typed.overrides = function(v) {
return new Typed(_gaurd, "overrides", Object.assign({}, v));
};
Typed.isTyped = function(value) {
return (value
&& typeof (value) === "object"
&& "_typedSymbol" in value
&& value._typedSymbol === _typedSymbol);
};
Typed.dereference = function(value, type) {
if (Typed.isTyped(value)) {
if (value.type !== type) {
throw new Error("invalid type: expecetd " + type + ", got " + value.type);
}
return value.value;
}
return value;
};
function Interface(fragments) {
var self = this;
var abi = [];
if (typeof (fragments) === "string") {
abi = JSON.parse(fragments);
}
else {
abi = fragments;
}
this._functions = new Map();
this._errors = new Map();
this._events = new Map();
// this._structs = new Map();
var frags = [];
for (var i = 0; i < abi.length; i++) {
try {
frags.push(Fragment.from(abi[i]));
}
catch (error) {
print("[Warning] Invalid Fragment " + JSON.stringify(abi[i]) + ":", error.message);
}
}
defineProperties(this, {
fragments: Object.freeze(frags)
});
var fallback = null;
var receive = false;
this._abiCoder = this.getAbiCoder();
// Add all fragments by their signature
this.fragments.forEach(function(fragment, index) {
var bucket;
switch (fragment.type) {
case "constructor":
if (self.deploy) {
print("duplicate definition - constructor");
return;
}
//checkNames(fragment, "input", fragment.inputs);
defineProperties(self, { deploy: fragment });
return;
case "fallback":
if (fragment.inputs.length === 0) {
receive = true;
}
else {
assertArgument(!fallback || fragment.payable !== fallback.payable, "conflicting fallback fragments", "fragments[" + index + "]", fragment);
fallback = fragment;
receive = fallback.payable;
}
return;
case "function":
//checkNames(fragment, "input", fragment.inputs);
//checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
bucket = self._functions;
break;
case "event":
//checkNames(fragment, "input", fragment.inputs);
bucket = self._events;
break;
case "error":
bucket = self._errors;
break;
default:
return;
}
// Two identical entries; ignore it
var signature = fragment.format();
if (bucket.has(signature)) {
return;
}
bucket.set(signature, fragment);
});
// If we do not have a constructor add a default
if (!this.deploy) {
defineProperties(this, {
deploy: ConstructorFragment.from("constructor()")
});
}
defineProperties(this, { fallback: fallback, receive: receive });
}
Interface.prototype.format = function(minimal) {
var format = (minimal ? "minimal" : "full");
var abi = this.fragments.map(function(f) { return f.format(format); });
return abi;
};
Interface.prototype.formatJson = function() {
var abi = this.fragments.map(function(f) { return f.format("json"); });
// We need to re-bundle the JSON fragments a bit
return JSON.stringify(abi.map(function(j) { return JSON.parse(j); }));
};
Interface.prototype.getAbiCoder = function() {
return AbiCoder.defaultAbiCoder();
};
Interface.prototype._getFunction = function(key, values, forceUnique) {
var self = this;
// Selector
if (isHexString(key)) {
var selector = key.toLowerCase();
var fns = this._functions.values();
for (let i = 0; i < fns.length; i++) {
const fragment = fns[i];
if (selector === fragment.selector) {
return fragment;
}
}
return null;
}
// It is a bare name, look up the function (will return null if ambiguous)
if (key.indexOf("(") === -1) {
var matching = [];
this._functions.forEach(function(fragment, name) {
if (name.split("(" /* fix:) */)[0] === key) {
matching.push(fragment);
}
});
if (values) {
var lastValue = (values.length > 0) ? values[values.length - 1] : null;
var valueLength = values.length;
var allowOptions = true;
if (Typed.isTyped(lastValue) && lastValue.type === "overrides") {
allowOptions = false;
valueLength--;
}
// Remove all matches that don't have a compatible length. The args
// may contain an overrides, so the match may have n or n - 1 parameters
for (var i = matching.length - 1; i >= 0; i--) {
var inputs = matching[i].inputs.length;
if (inputs !== valueLength && (!allowOptions || inputs !== valueLength - 1)) {
matching.splice(i, 1);
}
}
// Remove all matches that don't match the Typed signature
for (var i = matching.length - 1; i >= 0; i--) {
var inputs = matching[i].inputs;
for (var j = 0; j < values.length; j++) {
// Not a typed value
if (!Typed.isTyped(values[j])) {
continue;
}
// We are past the inputs
if (j >= inputs.length) {
if (values[j].type === "overrides") {
continue;
}
matching.splice(i, 1);
break;
}
// Make sure the value type matches the input type
if (values[j].type !== inputs[j].baseType) {
matching.splice(i, 1);
break;
}
}
}
}
// We found a single matching signature with an overrides, but the
// last value is something that cannot possibly be an options
if (matching.length === 1 && values && values.length !== matching[0].inputs.length) {
var lastArg = values[values.length - 1];
if (lastArg == null || Array.isArray(lastArg) || typeof (lastArg) !== "object") {
matching.splice(0, 1);
}
}
if (matching.length === 0) {
return null;
}
if (matching.length > 1 && forceUnique) {
var matchStr = matching.map(function(m) { return JSON.stringify(m.format()); }).join(", ");
assertArgument(false, "ambiguous function description (i.e. matches " + matchStr + ")", "key", key);
}
return matching[0];
}
// Normalize the signature and lookup the function
var result = this._functions.get(FunctionFragment.from(key).format());
if (result) {
return result;
}
return null;
};
Interface.prototype.getFunctionName = (key) => {
const fragment = this._getFunction(key, null, false);
assertArgument(fragment, "no matching function", "key", key);
return fragment.name;
}
/**
* Returns true if %%key%% (a function selector, function name or
* function signature) is present in the ABI.
*
* In the case of a function name, the name may be ambiguous, so
* accessing the [[FunctionFragment]] may require refinement.
*/
Interface.prototype.hasFunction = (key) => {
return !!this._getFunction(key, null, false);
}
/**
* Get the [[FunctionFragment]] for %%key%%, which may be a function
* selector, function name or function signature that belongs to the ABI.
*
* If %%values%% is provided, it will use the Typed API to handle
* ambiguous cases where multiple functions match by name.
*
* If the %%key%% and %%values%% do not refine to a single function in
* the ABI, this will throw.
*/
Interface.prototype.getFunction = (key, values) => {
return this._getFunction(key, values || null, true);
}
/**
* Iterate over all functions, calling %%callback%%, sorted by their name.
*/
Interface.prototype.forEachFunction = (callback) => {
const names = Array.from(this._functions.keys());
names.sort((a, b) => a.localeCompare(b));
for (let i = 0; i < names.length; i++) {
const name = names[i];
callback((this._functions.get(name)), i);
}
}
// Find an event definition by any means necessary (unless it is ambiguous)
Interface.prototype._getEvent = (key, values, forceUnique) => {
// EventTopic
if (isHexString(key)) {
const eventTopic = key.toLowerCase();
for (const fragment of this._events.values()) {
if (eventTopic === fragment.topicHash) {
return fragment;
}
}
return null;
}
// It is a bare name, look up the function (will return null if ambiguous)
if (key.indexOf("(") === -1) {
const matching = [];
this._events.forEach(function(fragment, name) {
if (name.split("(" /* fix:) */)[0] === key) {
matching.push(fragment);
}
});
if (values) {
// Remove all matches that don't have a compatible length.
for (let i = matching.length - 1; i >= 0; i--) {
if (matching[i].inputs.length < values.length) {
matching.splice(i, 1);
}
}
// Remove all matches that don't match the Typed signature
for (let i = matching.length - 1; i >= 0; i--) {
const inputs = matching[i].inputs;
for (let j = 0; j < values.length; j++) {
// Not a typed value
if (!Typed.isTyped(values[j])) {
continue;
}
// Make sure the value type matches the input type
if (values[j].type !== inputs[j].baseType) {
matching.splice(i, 1);
break;
}
}
}
}
if (matching.length === 0) {
return null;
}
if (matching.length > 1 && forceUnique) {
const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
assertArgument(false, `ambiguous event description (i.e. matches ${matchStr})`, "key", key);
}
return matching[0];
}
// Normalize the signature and lookup the function
const result = this._events.get(EventFragment.from(key).format());
if (result) {
return result;
}
return null;
}
/**
* Get the event name for %%key%%, which may be a topic hash,
* event name or event signature that belongs to the ABI.
*/
Interface.prototype.getEventName = (key) => {
const fragment = this._getEvent(key, null, false);
assertArgument(fragment, "no matching event", "key", key);
return fragment.name;
}
/**
* Returns true if %%key%% (an event topic hash, event name or
* event signature) is present in the ABI.
*
* In the case of an event name, the name may be ambiguous, so
* accessing the [[EventFragment]] may require refinement.
*/
Interface.prototype.hasEvent = (key) => {
return !!this._getEvent(key, null, false);
}
/**
* Get the [[EventFragment]] for %%key%%, which may be a topic hash,
* event name or event signature that belongs to the ABI.
*
* If %%values%% is provided, it will use the Typed API to handle
* ambiguous cases where multiple events match by name.
*
* If the %%key%% and %%values%% do not refine to a single event in
* the ABI, this will throw.
*/
Interface.prototype.getEvent = (key, values) => {
return this._getEvent(key, values || null, true);
}
/**
* Iterate over all events, calling %%callback%%, sorted by their name.
*/
Interface.prototype.forEachEvent = (callback) => {
const names = Array.from(this._events.keys());
names.sort((a, b) => a.localeCompare(b));
for (let i = 0; i < names.length; i++) {
const name = names[i];
callback((this._events.get(name)), i);
}
}
/**
* Get the [[ErrorFragment]] for %%key%%, which may be an error
* selector, error name or error signature that belongs to the ABI.
*
* If %%values%% is provided, it will use the Typed API to handle
* ambiguous cases where multiple errors match by name.
*
* If the %%key%% and %%values%% do not refine to a single error in
* the ABI, this will throw.
*/
Interface.prototype.getError = (key, values) => {
if (isHexString(key)) {
const selector = key.toLowerCase();
if (BuiltinErrors[selector]) {
return ErrorFragment.from(BuiltinErrors[selector].signature);
}
for (const fragment of this._errors.values()) {
if (selector === fragment.selector) {
return fragment;
}
}
return null;
}
// It is a bare name, look up the function (will return null if ambiguous)
if (key.indexOf("(") === -1) {
const matching = [];
this._errors.forEach(function(fragment, name) {
if (name.split("(" /* fix:) */)[0] === key) {
matching.push(fragment);
}
});
if (matching.length === 0) {
if (key === "Error") {
return ErrorFragment.from("error Error(string)");
}
if (key === "Panic") {
return ErrorFragment.from("error Panic(uint256)");
}
return null;
}
else if (matching.length > 1) {
const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
assertArgument(false, `ambiguous error description (i.e. ${matchStr})`, "name", key);
}
return matching[0];
}
// Normalize the signature and lookup the function
key = ErrorFragment.from(key).format();
if (key === "Error(string)") {
return ErrorFragment.from("error Error(string)");
}
if (key === "Panic(uint256)") {
return ErrorFragment.from("error Panic(uint256)");
}
const result = this._errors.get(key);
if (result) {
return result;
}
return null;
}
/**
* Iterate over all errors, calling %%callback%%, sorted by their name.
*/
Interface.prototype.forEachError = (callback) => {
const names = Array.from(this._errors.keys());
names.sort((a, b) => a.localeCompare(b));
for (let i = 0; i < names.length; i++) {
const name = names[i];
callback((this._errors.get(name)), i);
}
}
Interface.prototype._decodeParams = (params, data) => {
return this._abiCoder.decode(params, data);
}
Interface.prototype._encodeParams = (params, values) => {
return this._abiCoder.encode(params, values);
}
/**
* Encodes a ``tx.data`` object for deploying the Contract with
* the %%values%% as the constructor arguments.
*/
Interface.prototype.encodeDeploy = (values) => {
return this._encodeParams(this.deploy.inputs, values || []);
}
/**
* Decodes the result %%data%% (e.g. from an ``eth_call``) for the
* specified error (see [[getError]] for valid values for
* %%key%%).
*
* Most developers should prefer the [[parseCallResult]] method instead,
* which will automatically detect a ``CALL_EXCEPTION`` and throw the
* corresponding error.
*/
Interface.prototype.decodeErrorResult = (fragment, data) => {
if (typeof (fragment) === "string") {
const f = this.getError(fragment);
assertArgument(f, "unknown error", "fragment", fragment);
fragment = f;
}
assertArgument(dataSlice(data, 0, 4) === fragment.selector, `data signature does not match error ${fragment.name}.`, "data", data);
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
}
/**
* Encodes the transaction revert data for a call result that
* reverted from the the Contract with the sepcified %%error%%
* (see [[getError]] for valid values for %%fragment%%) with the %%values%%.
*
* This is generally not used by most developers, unless trying to mock
* a result from a Contract.
*/
Interface.prototype.encodeErrorResult = (fragment, values) => {
if (typeof (fragment) === "string") {
const f = this.getError(fragment);
assertArgument(f, "unknown error", "fragment", fragment);
fragment = f;
}
return concat([
fragment.selector,
this._encodeParams(fragment.inputs, values || [])
]);
}
/**
* Decodes the %%data%% from a transaction ``tx.data`` for
* the function specified (see [[getFunction]] for valid values
* for %%fragment%%).
*
* Most developers should prefer the [[parseTransaction]] method
* instead, which will automatically detect the fragment.
*/
Interface.prototype.decodeFunctionData = (fragment, data) => {
if (typeof (fragment) === "string") {
const f = this.getFunction(fragment);
assertArgument(f, "unknown function", "fragment", fragment);
fragment = f;
}
assertArgument(dataSlice(data, 0, 4) === fragment.selector, `data signature does not match function ${fragment.name}.`, "data", data);
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
}
/**
* Encodes the ``tx.data`` for a transaction that calls the function
* specified (see [[getFunction]] for valid values for %%fragment%%) with
* the %%values%%.
*/
Interface.prototype.encodeFunctionData = (fragment, values) => {
if (typeof (fragment) === "string") {
const f = this.getFunction(fragment);
assertArgument(f, "unknown function", "fragment", fragment);
fragment = f;
}
return concat([
fragment.selector,
this._encodeParams(fragment.inputs, values || [])
]);
}
/**
* Decodes the result %%data%% (e.g. from an ``eth_call``) for the
* specified function (see [[getFunction]] for valid values for
* %%key%%).
*
* Most developers should prefer the [[parseCallResult]] method instead,
* which will automatically detect a ``CALL_EXCEPTION`` and throw the
* corresponding error.
*/
Interface.prototype.decodeFunctionResult = (fragment, data) => {
if (typeof (fragment) === "string") {
const f = this.getFunction(fragment);
assertArgument(f, "unknown function", "fragment", fragment);
fragment = f;
}
let message = "invalid length for result data";
const bytes = getBytesCopy(data, "decode result");
if ((bytes.length % 32) === 0) {
try {
return this._abiCoder.decode(fragment.outputs, bytes);
}
catch (error) {
print(error, error.stack)
message = "could not decode result data";
}
}
// Call returned data with no error, but the data is junk
assert(false, message, "BAD_DATA", {
value: hexlify(bytes),
info: { method: fragment.name, signature: fragment.format() }
});
}
Interface.prototype.makeError = (_data, tx) => {
const data = getBytes(_data, "data");
const error = AbiCoder.getBuiltinCallException("call", tx, data);
// Not a built-in error; try finding a custom error
const customPrefix = "execution reverted (unknown custom error)";
if (error.message.startsWith(customPrefix)) {
const selector = hexlify(data.slice(0, 4));
const ef = this.getError(selector);
if (ef) {
try {
const args = this._abiCoder.decode(ef.inputs, data.slice(4));
error.revert = {
name: ef.name, signature: ef.format(), args: args
};
error.reason = error.revert.signature;
error.message = `execution reverted: ${error.reason}`;
}
catch (e) {
error.message = `execution reverted (coult not decode custom error)`;
}
}
}
// Add the invocation, if available
const parsed = this.parseTransaction(tx);
if (parsed) {
error.invocation = {
method: parsed.name,
signature: parsed.signature,
args: parsed.args
};
}
return error;
}
/**
* Encodes the result data (e.g. from an ``eth_call``) for the
* specified function (see [[getFunction]] for valid values
* for %%fragment%%) with %%values%%.
*
* This is generally not used by most developers, unless trying to mock
* a result from a Contract.
*/
Interface.prototype.encodeFunctionResult = (fragment, values) => {
if (typeof (fragment) === "string") {
const f = this.getFunction(fragment);
assertArgument(f, "unknown function", "fragment", fragment);
fragment = f;
}
return hexlify(this._abiCoder.encode(fragment.outputs, values || []));
}
// Create the filter for the event with search criteria (e.g. for eth_filterLog)
Interface.prototype.encodeFilterTopics = (fragment, values) => {
if (typeof (fragment) === "string") {
const f = this.getEvent(fragment);
assertArgument(f, "unknown event", "eventFragment", fragment);
fragment = f;
}
assert(values.length <= fragment.inputs.length, `too many arguments for ${fragment.format()}`, "UNEXPECTED_ARGUMENT", { count: values.length, expectedCount: fragment.inputs.length });
const topics = [];
if (!fragment.anonymous) {
topics.push(fragment.topicHash);
}
// @TODO: Use the coders for this; to properly support tuples, etc.
const encodeTopic = (param, value) => {
if (param.type === "string") {
return id(value);
}
else if (param.type === "bytes") {
return keccak256(hexlify(value));
}
if (param.type === "bool" && typeof (value) === "boolean") {
value = (value ? "0x01" : "0x00");
}
else if (param.type.match(/^u?int/)) {
value = toBeHex(value); // @TODO: Should this toTwos??
}
else if (param.type.match(/^bytes/)) {
value = zeroPadBytes(value, 32);
}
else if (param.type === "address") {
// Check addresses are valid
this._abiCoder.encode(["address"], [value]);
}
return zeroPadValue(hexlify(value), 32);
};
values.forEach((value, index) => {
const param = fragment.inputs[index];
if (!param.indexed) {
assertArgument(value == null, "cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
return;
}
if (value == null) {
topics.push(null);
}
else if (param.baseType === "array" || param.baseType === "tuple") {
assertArgument(false, "filtering with tuples or arrays not supported", ("contract." + param.name), value);
}
else if (Array.isArray(value)) {
topics.push(value.map((value) => encodeTopic(param, value)));
}
else {
topics.push(encodeTopic(param, value));
}
});
// Trim off trailing nulls
while (topics.length && topics[topics.length - 1] === null) {
topics.pop();
}
return topics;
}
Interface.prototype.encodeEventLog = (fragment, values) => {
if (typeof (fragment) === "string") {
const f = this.getEvent(fragment);
assertArgument(f, "unknown event", "eventFragment", fragment);
fragment = f;
}
const topics = [];
const dataTypes = [];
const dataValues = [];
if (!fragment.anonymous) {
topics.push(fragment.topicHash);
}
assertArgument(values.length === fragment.inputs.length, "event arguments/values mismatch", "values", values);
fragment.inputs.forEach((param, index) => {
const value = values[index];
if (param.indexed) {
if (param.type === "string") {
topics.push(id(value));
}
else if (param.type === "bytes") {
topics.push(keccak256(value));
}
else if (param.baseType === "tuple" || param.baseType === "array") {
// @TODO
throw new Error("not implemented");
}
else {
topics.push(this._abiCoder.encode([param.type], [value]));
}
}
else {
dataTypes.push(param);
dataValues.push(value);
}
});
return {
data: this._abiCoder.encode(dataTypes, dataValues),
topics: topics
};
}
// Decode a filter for the event and the search criteria
Interface.prototype.decodeEventLog = (fragment, data, topics) => {
if (typeof (fragment) === "string") {
const f = this.getEvent(fragment);
assertArgument(f, "unknown event", "eventFragment", fragment);
fragment = f;
}
if (topics != null && !fragment.anonymous) {
const eventTopic = fragment.topicHash;
assertArgument(isHexString(topics[0], 32) && topics[0].toLowerCase() === eventTopic, "fragment/topic mismatch", "topics[0]", topics[0]);
topics = topics.slice(1);
}
const indexed = [];
const nonIndexed = [];
const dynamic = [];
fragment.inputs.forEach((param, index) => {
if (param.indexed) {
if (param.type === "string" || param.type === "bytes" || param.baseType === "tuple" || param.baseType === "array") {
indexed.push(ParamType.from({ type: "bytes32", name: param.name }));
dynamic.push(true);
}
else {
indexed.push(param);
dynamic.push(false);
}
}
else {
nonIndexed.push(param);
dynamic.push(false);
}
});
const resultIndexed = (topics != null) ? this._abiCoder.decode(indexed, concat(topics)) : null;
const resultNonIndexed = this._abiCoder.decode(nonIndexed, data, true);
//const result: (Array<any> & { [ key: string ]: any }) = [ ];
const values = [];
const keys = [];
let nonIndexedIndex = 0, indexedIndex = 0;
fragment.inputs.forEach((param, index) => {
let value = null;
if (param.indexed) {
if (resultIndexed == null) {
value = new Indexed(null);
}
else if (dynamic[index]) {
value = new Indexed(resultIndexed[indexedIndex++]);
}
else {
try {
value = resultIndexed[indexedIndex++];
}
catch (error) {
value = error;
}
}
}
else {
try {
value = resultNonIndexed[nonIndexedIndex++];
}
catch (error) {
value = error;
}
}
values.push(value);
keys.push(param.name || null);
});
return values;
}
/**
* Parses a transaction, finding the matching function and extracts
* the parameter values along with other useful function details.
*
* If the matching function cannot be found, return null.
*/
Interface.prototype.parseTransaction = (tx) => {
const data = getBytes(tx.data, "tx.data");
const value = getBigInt((tx.value != null) ? tx.value : 0, "tx.value");
const fragment = this.getFunction(hexlify(data.slice(0, 4)));
if (!fragment) {
return null;
}
const args = this._abiCoder.decode(fragment.inputs, data.slice(4));
return new TransactionDescription(fragment, fragment.selector, args, value);
}
Interface.prototype.parseCallResult = function(data) {
throw new Error("@TODO");
}
/**
* Parses a receipt log, finding the matching event and extracts
* the parameter values along with other useful event details.
*
* If the matching event cannot be found, returns null.
*/
Interface.prototype.parseLog = function(log) {
const fragment = this.getEvent(log.topics[0]);
if (!fragment || fragment.anonymous) {
return null;
}
// @TODO: If anonymous, and the only method, and the input count matches, should we parse?
// Probably not, because just because it is the only event in the ABI does
// not mean we have the full ABI; maybe just a fragment?
return new LogDescription(fragment, fragment.topicHash, this.decodeEventLog(fragment, log.data, log.topics));
}
/**
* Parses a revert data, finding the matching error and extracts
* the parameter values along with other useful error details.
*
* If the matching error cannot be found, returns null.
*/
Interface.prototype.parseError = function(data) {
const hexData = hexlify(data);
const fragment = this.getError(dataSlice(hexData, 0, 4));
if (!fragment) {
return null;
}
const args = this._abiCoder.decode(fragment.inputs, dataSlice(hexData, 4));
return new ErrorDescription(fragment, fragment.selector, args);
}
/**
* Creates a new [[Interface]] from the ABI %%value%%.
*
* The %%value%% may be provided as an existing [[Interface]] object,
* a JSON-encoded ABI or any Human-Readable ABI format.
*/
Interface.from = function(value) {
// Already an Interface, which is immutable
if (value instanceof Interface) {
return value;
}
// JSON
if (typeof (value) === "string") {
return new Interface(JSON.parse(value));
}
// An Interface; possibly from another v6 instance
if (typeof (value.formatJson) === "function") {
return new Interface(value.formatJson());
}
// A legacy Interface; from an older version
if (typeof (value.format) === "function") {
return new Interface(value.format("json"));
}
// Array of fragments
return new Interface(value);
}
// Additional methods...
function BaseContract(target, abi, runner, _deployTx) {
var self = this;
assertArgument(typeof (target) === "string" || isAddressable(target), "invalid value for Contract target", "target", target);
if (runner == null) {
runner = null;
}
var iface = Interface.from(abi);
defineProperties(this, {
target: target,
runner: runner,
interface: iface
});
this.internal = { value: {} };
var addr = null;
var deployTx = null;
if (_deployTx) {
var provider = getProvider(runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
deployTx = new ContractTransactionResponse(this.interface, provider, _deployTx);
}
var subs = new Map();
// Resolve the target as the address
if (typeof (target) === "string") {
if (isHexString(target)) {
addr = target;
}
else {
var resolver = getRunner(runner, "resolveName");
if (!canResolve(resolver)) {
throw makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
operation: "resolveName"
});
}
addr = resolver.resolveName(target);
if (addr == null) {
throw makeError("an ENS name used for a contract target must be correctly configured", "UNCONFIGURED_NAME", { value: target });
}
}
}
else {
addr = target.getAddress();
if (addr == null) {
throw new Error("TODO");
}
}
// Set our private values
this.internal = { addr: addr, deployTx: deployTx, subs: subs };
// Add the event filters
var filters = new Proxy({}, {
get: function(target, prop, receiver) {
// 处理特殊属性(如Promise的then等)
if (typeof (prop) === "symbol" || passProperties.indexOf(prop) >= 0) {
return target[prop]; // 使用直接属性访问替代Reflect.get
}
try {
return self.getEvent(prop);
} catch (error) {
if (!isError(error, "INVALID_ARGUMENT") || error.argument !== "key") {
throw error;
}
}
return undefined;
},
has: function(target, prop) {
if (passProperties.indexOf(prop) >= 0) {
return prop in target; // 使用 in 操作符替代Reflect.has
}
return (prop in target) || self.interface.hasEvent(String(prop));
}
});
defineProperties(this, { filters: filters });
defineProperties(this, {
fallback: ((iface.receive || iface.fallback) ? (buildWrappedFallback(this)) : null)
});
// Return a Proxy that will respond to functions
return new Proxy(this, {
get: function(target, prop, receiver) {
if (typeof (prop) === "symbol" || prop in target || passProperties.indexOf(prop) >= 0) {
return target[prop];
}
// Undefined properties should return undefined
try {
return target.getFunction(prop);
}
catch (error) {
if (!isError(error, "INVALID_ARGUMENT") || error.argument !== "key") {
throw error;
}
}
return undefined;
},
has: function(target, prop) {
if (typeof (prop) === "symbol" || prop in target || passProperties.indexOf(prop) >= 0) {
return prop in target;
}
return target.interface.hasFunction(prop);
}
});
}
BaseContract.prototype.connect = function(runner) {
return new BaseContract(this.target, this.interface, runner);
};
BaseContract.prototype.attach = function(target) {
return new BaseContract(target, this.interface, this.runner);
};
BaseContract.prototype.getAddress = function() {
return this.internal.addr;
};
BaseContract.prototype.getDeployedCode = function() {
var provider = getProvider(this.runner);
assert(provider, "runner does not support .provider", "UNSUPPORTED_OPERATION", { operation: "getDeployedCode" });
var code = provider.getCode(this.getAddress());
if (code === "0x") {
return null;
}
return code;
};
BaseContract.prototype.waitForDeployment = function(interval, timeout) {
// We have the deployement transaction; just use that (throws if deployement fails)
var deployTx = this.deploymentTransaction();
if (deployTx) {
deployTx.wait();
return this;
}
// Check for code
var code = this.getDeployedCode();
if (code != null) {
return this;
}
// Make sure we can subscribe to a provider event
var provider = getProvider(this.runner);
assert(provider != null, "contract runner does not support .provider", "UNSUPPORTED_OPERATION", { operation: "waitForDeployment" });
var nowTs = Date.now();
while(Date.now() - nowTs > timeout) {
wait(interval);
var code = this.getDeployedCode();
if (code != null) {
return this;
}
}
throw makeError("wait for contract deployment timeout", "TIMEOUT", { operation: "waitForDeployment"});
};
BaseContract.prototype.deploymentTransaction = function() {
return this.internal.deployTx;
};
BaseContract.prototype.getFunction = function(key) {
if (typeof (key) !== "string") {
key = key.format();
}
var func = buildWrappedMethod(this, key);
return func;
};
BaseContract.prototype.getEvent = function(key) {
if (typeof (key) !== "string") {
key = key.format();
}
return buildWrappedEvent(this, key);
};
BaseContract.prototype.queryTransaction = function(hash) {
throw new Error("@TODO");
};
BaseContract.prototype.queryFilter = function(event, fromBlock, toBlock) {
var self = this;
if (fromBlock == null) {
fromBlock = 0;
}
if (toBlock == null) {
toBlock = "latest";
}
var internal = this.internal;
var address = internal.addr;
var subInfo = getSubInfo(this, event);
var fragment = subInfo.fragment;
var topics = subInfo.topics;
var filter = { address: address, topics: topics, fromBlock: fromBlock, toBlock: toBlock };
var provider = getProvider(this.runner);
assert(provider, "contract runner does not have a provider", "UNSUPPORTED_OPERATION", { operation: "queryFilter" });
return (provider.getLogs(filter)).map(function(log) {
var foundFragment = fragment;
if (foundFragment == null) {
try {
foundFragment = self.interface.getEvent(log.topics[0]);
}
catch (error) { }
}
if (foundFragment) {
try {
return new EventLog(log, self.interface, foundFragment);
}
catch (error) {
return new UndecodedEventLog(log, error);
}
}
return new Log(log, provider);
});
};
BaseContract.buildClass = function(abi) {
function CustomContract(address, runner) {
if (runner === undefined) runner = null;
BaseContract.call(this, address, abi, runner);
}
CustomContract.prototype = Object.create(BaseContract.prototype);
CustomContract.prototype.constructor = CustomContract;
return CustomContract;
};
BaseContract.from = function(target, abi, runner) {
if (runner == null) {
runner = null;
}
return new this(target, abi, runner);
};
function JsonRpcProvider(url, network) {
var self = this;
// 私有属性
var _url = url || "http://localhost:8545";
var _nextId = 1; // JSON-RPC请求ID
// 基础JSON-RPC调用方法
function send(method, params) {
var request = {
url: _url,
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
jsonrpc: "2.0",
id: (_nextId++),
method: method,
params: params || []
})
};
var resp;
try {
resp = fetch(request);
}
catch (_error) {
throw _error;
}
const respBody = JSON.parse(resp.body());
// The response is an error
if ("error" in respBody) {
throw this.getRpcError(request, resp);
}
// All good; send the result
return respBody.result;
}
// 基础方法实现
this.call = function(transaction) {
return send("eth_call", [{
to: transaction.to,
data: transaction.data,
from: transaction.from,
value: transaction.value ? "0x" + transaction.value.toString(16) : undefined
}, "latest"]);
};
this.getBalance = function(address) {
return send("eth_getBalance", [address, "latest"]).then(function(result) {
return BigInt(result);
});
};
this.getTransactionCount = function(address) {
return send("eth_getTransactionCount", [address, "latest"]).then(function(result) {
return parseInt(result, 16);
});
};
this.getCode = function(address) {
return send("eth_getCode", [address, "latest"]);
};
this.getBlock = function(blockNumber) {
var tag = (typeof blockNumber === "number") ?
"0x" + blockNumber.toString(16) :
blockNumber;
return send("eth_getBlockByNumber", [tag, false]);
};
this.getTransaction = function(hash) {
return send("eth_getTransactionByHash", [hash]);
};
this.getTransactionReceipt = function(hash) {
return send("eth_getTransactionReceipt", [hash]);
};
this.sendTransaction = function(signedTx) {
return send("eth_sendRawTransaction", [signedTx]);
};
// 事件相关
this.getLogs = function(filter) {
return send("eth_getLogs", [filter]);
};
// 工具方法
this.estimateGas = function(tx) {
return send("eth_estimateGas", [tx]).then(function(result) {
return BigInt(result);
});
};
// 网络相关
this.getNetwork = function() {
return send("eth_chainId").then(function(chainId) {
return {
chainId: parseInt(chainId, 16),
name: getNetworkName(parseInt(chainId, 16))
};
});
};
// 辅助函数
function getNetworkName(chainId) {
var networks = {
1: "mainnet",
3: "ropsten",
4: "rinkeby",
5: "goerli",
42: "kovan"
};
return networks[chainId] || "unknown";
}
// 初始化
if (network) {
this._network = network;
}
}
return {
Contract: BaseContract,
JsonRpcProvider: JsonRpcProvider
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment