Beta 7 with some repo names changed.
This commit is contained in:
1 parent
0f7b40cca7
commit
963c19493a
3408 files changed
+462217
-15516
No files matched your search
+195
@@ -0,0 +1,195 @@
|
||||
const Api = provider => {
|
||||
const Nat = require("./nat");
|
||||
const Map = require("./map");
|
||||
const Bytes = require("./bytes");
|
||||
const keccak256s = require("./hash").keccak256s;
|
||||
const send = method => (...params) =>
|
||||
new Promise((resolve,reject) =>
|
||||
provider.send(method, params, (err, result) =>
|
||||
err ? reject(err) : resolve(result)));
|
||||
|
||||
// TODO check inputs
|
||||
// TODO move to proper file
|
||||
const encodeABI = (type, value) => {
|
||||
if (type === "bytes") {
|
||||
const length = Bytes.length(value);
|
||||
const nextMul32 = (((length - 1) / 32 | 0) + 1) * 32;
|
||||
const lengthEncoded = encodeABI("uint256", Nat.fromNumber(length)).data;
|
||||
const bytesEncoded = Bytes.padRight(nextMul32, value);
|
||||
return {data: Bytes.concat(lengthEncoded, bytesEncoded), dynamic: true};
|
||||
} else if (type === "uint256" || type === "bytes32") {
|
||||
return {data: Bytes.pad(32, value), dynamic: false};
|
||||
} else {
|
||||
throw "Eth-lib can't encode ABI type " + type + " yet.";
|
||||
}
|
||||
}
|
||||
|
||||
const sendTransaction = send("eth_sendTransaction");
|
||||
const sendRawTransaction = send("eth_sendRawTransaction");
|
||||
const getTransactionReceipt = send("eth_getTransactionReceipt");
|
||||
const compileSolidity = send("eth_compileSolidity");
|
||||
const call = send("eth_call");
|
||||
const getBalance = send("eth_getBalance");
|
||||
const accounts = send("eth_accounts");
|
||||
|
||||
const removeEmptyTo = tx =>
|
||||
tx.to === "" || tx.to === "0x" ? Map.remove("to")(tx) : tx;
|
||||
|
||||
const waitTransactionReceipt = getTransactionReceipt; // TODO: implement correctly
|
||||
|
||||
const addTransactionDefaults = tx =>
|
||||
// Get basic defaults
|
||||
Promise.all([
|
||||
tx.chainId || send("net_version")(),
|
||||
tx.gasPrice || send("eth_gasPrice")(),
|
||||
tx.nonce || send("eth_getTransactionCount")(tx.from,"latest"),
|
||||
tx.value || "0x0",
|
||||
tx.data || "0x"])
|
||||
// Add them to tx
|
||||
.then(([chainId, gasPrice, nonce, value, data]) => {
|
||||
return Map.merge(tx)({chainId: Nat.fromNumber(chainId), gasPrice, nonce, value, data});
|
||||
})
|
||||
.then(tx => {
|
||||
// Add gas default by estimating
|
||||
if (!tx.gas) {
|
||||
let estimateTx = {};
|
||||
estimateTx.from = tx.from;
|
||||
if (tx.to !== "" && tx.to !== "0x")
|
||||
estimateTx.to = tx.to;
|
||||
estimateTx.value = tx.value;
|
||||
estimateTx.nonce = tx.nonce;
|
||||
estimateTx.data = tx.data;
|
||||
return send("eth_estimateGas")(estimateTx)
|
||||
.then(usedGas => {
|
||||
return Map.merge(tx)({gas: Nat.div(Nat.mul(usedGas,"0x6"),"0x5")});
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(tx);
|
||||
}
|
||||
});
|
||||
|
||||
const sendTransactionWithDefaults = tx =>
|
||||
addTransactionDefaults(tx)
|
||||
.then(tx => sendTransaction(removeEmptyTo(tx)));
|
||||
|
||||
const callWithDefaults = (tx, block) =>
|
||||
addTransactionDefaults(tx)
|
||||
.then(tx => call(removeEmptyTo(tx), block || "latest"));
|
||||
|
||||
const callMethodData = method => (...params) => {
|
||||
const methodSig = method.name + "(" + method.inputs.map(i => i.type).join(",") + ")";
|
||||
const methodHash = keccak256s(methodSig).slice(0,10);
|
||||
let encodedParams = params.map((param,i) => encodeABI(method.inputs[i].type, param));
|
||||
var headBlock = "0x";
|
||||
let dataBlock = "0x";
|
||||
for (var i = 0; i < encodedParams.length; ++i) {
|
||||
if (encodedParams[i].dynamic) {
|
||||
var dataLoc = encodedParams.length * 32 + Bytes.length(dataBlock);
|
||||
headBlock = Bytes.concat(headBlock, Bytes.pad(32, Nat.fromNumber(dataLoc)));
|
||||
dataBlock = Bytes.concat(dataBlock, encodedParams[i].data);
|
||||
} else {
|
||||
headBlock = Bytes.concat(headBlock, encodedParams[i].data);
|
||||
}
|
||||
}
|
||||
return Bytes.flatten([methodHash, headBlock, dataBlock]);
|
||||
}
|
||||
|
||||
// Address, Address, ContractInterface -> Contract
|
||||
const contract = (from, address, contractInterface) => {
|
||||
let contract = {};
|
||||
contract._address = address;
|
||||
contract._from = from;
|
||||
contract.broadcast = {};
|
||||
contractInterface.forEach(method => {
|
||||
if (method && method.name) {
|
||||
const call = (type, value) => (...params) => {
|
||||
const transaction = {
|
||||
from: from,
|
||||
to: address,
|
||||
value: value,
|
||||
data: callMethodData(method)(...params)
|
||||
};
|
||||
return type === "data"
|
||||
? Promise.resolve(transaction)
|
||||
: method.constant
|
||||
? callWithDefaults(transaction)
|
||||
: sendTransactionWithDefaults(transaction)
|
||||
.then(type === "receipt" ? waitTransactionReceipt : (x => x));
|
||||
};
|
||||
contract[method.name] = call("receipt", "0x0");
|
||||
if (!method.constant) {
|
||||
contract[method.name+"_data"] = call("data", "0x0");
|
||||
contract[method.name+"_pay"] = value => (...params) => call("receipt", value)(...params);
|
||||
contract[method.name+"_pay_txHash"] = value => (...params) => call("txHash", value)(...params);
|
||||
contract[method.name+"_txHash"] = call("txHash", "0x0");
|
||||
}
|
||||
}
|
||||
});
|
||||
return contract;
|
||||
}
|
||||
|
||||
// Address, Bytecode -> TxHash
|
||||
const deployBytecode_txHash = (from, code) =>
|
||||
sendTransactionWithDefaults({from: from, data: code, to: ""});
|
||||
|
||||
// Address, Bytecode -> Receipt
|
||||
const deployBytecode = (from, code) =>
|
||||
deployBytecode_txHash(from,code)
|
||||
.then(waitTransactionReceipt);
|
||||
|
||||
// Address, Bytecode, ContractInterface
|
||||
const deployBytecodeContract = (from, code, contractInterface) =>
|
||||
deployBytecode(from, code)
|
||||
.then(receipt => contract(from, receipt.contractAddress, contractInterface));
|
||||
|
||||
// Address, String, Address -> Contract
|
||||
const solidityContract = (from, source, at) =>
|
||||
compileSolidity(source)
|
||||
.then(({info:{abiDefinition}}) => contract(from, at, abiDefinition));
|
||||
|
||||
// Address, String -> TxHash
|
||||
const deploySolidity_txHash = (from, source) =>
|
||||
compileSolidity(source)
|
||||
.then(({code}) => deployBytecode_txHash(from, code));
|
||||
|
||||
// Address, String -> Receipt
|
||||
const deploySolidity = (from, source) =>
|
||||
deploySolidity_txHash(from, source)
|
||||
.then(waitTransactionReceipt);
|
||||
|
||||
// Address, String -> Contract
|
||||
const deploySolidityContract = (from, source) =>
|
||||
compileSolidity(source)
|
||||
.then(({code, info:{abiDefinition}}) =>
|
||||
deployBytecodeContract(from, code, abiDefinition));
|
||||
|
||||
return {
|
||||
send,
|
||||
|
||||
sendTransaction,
|
||||
sendRawTransaction,
|
||||
getTransactionReceipt,
|
||||
call,
|
||||
getBalance,
|
||||
accounts,
|
||||
|
||||
waitTransactionReceipt,
|
||||
addTransactionDefaults,
|
||||
sendTransactionWithDefaults,
|
||||
callWithDefaults,
|
||||
callMethodData,
|
||||
|
||||
contract,
|
||||
deployBytecode_txHash,
|
||||
deployBytecode,
|
||||
deployBytecodeContract,
|
||||
|
||||
compileSolidity,
|
||||
solidityContract,
|
||||
deploySolidity_txHash,
|
||||
deploySolidity,
|
||||
deploySolidityContract
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Api;
|
||||
Reference in new issue
Block a user