check-ethereum-scanner
Version:
Safety checks for new Ethereum tokens
84 lines (74 loc) • 3.02 kB
JavaScript
const F = require("forall");
const A = require("./array");
const B = require("./bytes");
const Account = require("./account");
F.Bytes = F(F.Type, {
form: "a JavaScript String starting with a `0x`, followed by an even number of low-case hex chars (i.e., `0123456789abcdef`)",
rand: () => "0x" + A.generate((Math.random() * 16 | 0) * 2, () => (Math.random() * 16 | 0).toString(16)).join(""),
test: value => typeof value === "string" && /^0x([0-9a-f][0-9a-f])*$/.test(value),
}).__name("Bytes").__desc("any arbitrary data");
F.NBytes = bytes => F(F.Type, {
form: "a JavaScript String starting with a `0x`, followed by " + (bytes * 2) + " low-case hex chars (i.e., `0123456789abcdef`)",
test: value => F.Bytes.test(value) && value.length === (bytes * 2 + 2),
rand: () => "0x" + A.generate(bytes * 2, () => (Math.random() * 16 | 0).toString(16)).join("")
})
.__name("NBytes(" + bytes + ")")
.__desc("any arbitrary data of exactly " + bytes + "-byte" + (bytes > 1 ? "s" : ""));
F.Nat = F(F.Type, {
form: "a JavaScript String starting with a `0x`, followed by at least one low-case hex char different from 0, followed by any number of low-case hex chars (i.e., `0123456789abcdef`)",
test: value => typeof value === "string" && /^0x[1-9a-f]([0-9a-f])*$/.test(value),
rand: () => "0x" + (Math.random() * Math.pow(2,50) | 0).toString(16)
})
.__name("Nat")
.__desc("an arbitrarily long non-negative integer number");
F.Address = F(F.Type, {
form: "a JavaScript String starting with a `0x`, followed by 40 hex chars (i.e., `0123456789abcdefABCDEF`), with the nth hex being uppercase iff the nth hex of the keccak256 of the lowercase address in ASCII is > 7",
test: address => /^(0x)?[0-9a-f]{40}$/i.test(address) && Account.toChecksum(address.toLowerCase()) === address,
rand: () => F.Account.rand().address
})
.__name("Address")
.__desc("an Ethereum public address");
F.Hash = F(F.Type, {
form: F.NBytes(32).form,
test: F.NBytes(32).test,
rand: F.NBytes(32).rand
})
.__name("Hash")
.__desc("a Keccak-256 hash");
F.PrivateKey = F(F.Type, {
form: F.NBytes(32).form,
test: F.NBytes(32).test,
rand: F.NBytes(32).rand
})
.__name("PrivateKey")
.__desc("an Ethereum private key");
F.Account = (() => {
const base = F.Struct({
address: F.Address,
privateKey: F.PrivateKey,
});
return F(F.Type, {
form: base.form,
test: base.test,
rand: () => Account.create("")
});
})()
.__name("Account")
.__desc("an Ethereum account");
F.BytesTree = F(F.Type, {
form: "either " + F.Bytes.form + ", or a tree of nested JavaScript Arrays of BytesTrees",
test: value => F.Bytes.test(value) || value instanceof Array && value.reduce((r,v) => F.BytesTree.test(v) && r, true),
rand: () => {
let list = [];
while (Math.random() < 0.8) {
if (Math.random() < 0.8)
list.push(F.Bytes.rand());
else
list.push(F.BytesTree.rand());
}
return list;
}
})
.__name("BytesTree")
.__desc("a tree of arbitrary binary data");
module.exports = F;