airgap-coin-lib
Version:
The airgap-coin-lib is a protocol agnostic library to prepare, sign and broadcast cryptocurrency transactions.
346 lines • 16.5 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var RPCBody_1 = require("../../../../data/RPCBody");
var index_1 = require("../../../../dependencies/src/axios-0.19.0/index");
var bignumber_1 = require("../../../../dependencies/src/bignumber.js-9.0.0/bignumber");
var IAirGapTransaction_1 = require("../../../../interfaces/IAirGapTransaction");
var EthereumProtocolOptions_1 = require("../../EthereumProtocolOptions");
var utils_1 = require("../../utils/utils");
var NodeClient_1 = require("./NodeClient");
var EthereumRPCBody = /** @class */ (function (_super) {
__extends(EthereumRPCBody, _super);
function EthereumRPCBody() {
return _super !== null && _super.apply(this, arguments) || this;
}
EthereumRPCBody.prototype.toRPCBody = function () {
return JSON.stringify(this.toJSON());
};
EthereumRPCBody.prototype.toJSON = function () {
return {
jsonrpc: this.jsonrpc,
method: this.method,
params: this.params,
id: this.id
};
};
EthereumRPCBody.blockEarliest = 'earliest';
EthereumRPCBody.blockLatest = 'latest';
EthereumRPCBody.blockPending = 'pending';
return EthereumRPCBody;
}(RPCBody_1.RPCBody));
var EthereumRPCData = /** @class */ (function () {
function EthereumRPCData(methodSignature) {
this.methodSignature = methodSignature;
}
EthereumRPCData.prototype.abiEncoded = function () {
var hash = utils_1.EthereumUtils.sha3(this.methodSignature);
if (hash === null) {
return '';
}
return "0x" + hash.slice(2, 10);
};
EthereumRPCData.addLeadingZeroPadding = function (value, targetLength) {
if (targetLength === void 0) { targetLength = EthereumRPCData.parametersLength; }
var result = value;
while (result.length < targetLength) {
result = '0' + result;
}
return result;
};
EthereumRPCData.removeLeadingZeroPadding = function (value) {
var result = value;
while (result.startsWith('0')) {
result = result.slice(1); // this can probably be done much more efficiently with a regex
}
return result;
};
// 2 chars = 1 byte hence to get to 32 bytes we need 64 chars
EthereumRPCData.parametersLength = 64;
return EthereumRPCData;
}());
exports.EthereumRPCData = EthereumRPCData;
var EthereumRPCDataBalanceOf = /** @class */ (function (_super) {
__extends(EthereumRPCDataBalanceOf, _super);
function EthereumRPCDataBalanceOf(address) {
var _this = _super.call(this, EthereumRPCDataBalanceOf.methodName + "(address)") || this;
_this.address = address;
return _this;
}
EthereumRPCDataBalanceOf.prototype.abiEncoded = function () {
var srcAddress = this.address;
if (srcAddress.startsWith('0x')) {
srcAddress = srcAddress.slice(2);
}
return _super.prototype.abiEncoded.call(this) + EthereumRPCData.addLeadingZeroPadding(srcAddress);
};
EthereumRPCDataBalanceOf.methodName = 'balanceOf';
return EthereumRPCDataBalanceOf;
}(EthereumRPCData));
exports.EthereumRPCDataBalanceOf = EthereumRPCDataBalanceOf;
var EthereumRPCDataTransfer = /** @class */ (function (_super) {
__extends(EthereumRPCDataTransfer, _super);
function EthereumRPCDataTransfer(toAddressOrData, amount) {
var _this = _super.call(this, EthereumRPCDataTransfer.methodName + "(address,uint256)") || this;
if (amount) {
var toAddress = toAddressOrData;
_this.recipient = toAddress;
_this.amount = amount;
}
else {
var data = toAddressOrData;
var methodID = _super.prototype.abiEncoded.call(_this);
if (!data.startsWith(methodID)) {
throw new Error('unexpected method ID');
}
var params = data.slice(methodID.length);
var recipient = EthereumRPCData.removeLeadingZeroPadding(params.slice(0, EthereumRPCData.parametersLength));
var parsedAmount = EthereumRPCData.removeLeadingZeroPadding(params.slice(EthereumRPCData.parametersLength));
_this.recipient = "0x" + recipient;
_this.amount = "0x" + parsedAmount;
}
return _this;
}
EthereumRPCDataTransfer.prototype.abiEncoded = function () {
var dstAddress = this.recipient;
if (dstAddress.startsWith('0x')) {
dstAddress = dstAddress.slice(2);
}
var transferAmount = this.amount;
if (transferAmount.startsWith('0x')) {
transferAmount = transferAmount.slice(2);
}
return (_super.prototype.abiEncoded.call(this) +
EthereumRPCData.addLeadingZeroPadding(dstAddress.toLowerCase()) +
EthereumRPCData.addLeadingZeroPadding(transferAmount.toLowerCase()));
};
EthereumRPCDataTransfer.methodName = 'transfer';
return EthereumRPCDataTransfer;
}(EthereumRPCData));
exports.EthereumRPCDataTransfer = EthereumRPCDataTransfer;
var AirGapNodeClient = /** @class */ (function (_super) {
__extends(AirGapNodeClient, _super);
function AirGapNodeClient(baseURL) {
if (baseURL === void 0) { baseURL = EthereumProtocolOptions_1.NODE_URL; }
return _super.call(this, baseURL) || this;
}
AirGapNodeClient.prototype.fetchBalance = function (address) {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_getBalance', [address, EthereumRPCBody.blockLatest]);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, new bignumber_1.BigNumber(response.result)];
}
});
});
};
AirGapNodeClient.prototype.fetchTransactionCount = function (address) {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_getTransactionCount', [address, EthereumRPCBody.blockLatest]);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, new bignumber_1.BigNumber(response.result).toNumber()];
}
});
});
};
AirGapNodeClient.prototype.sendSignedTransaction = function (transaction) {
return __awaiter(this, void 0, void 0, function () {
var body;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_sendRawTransaction', [transaction]);
return [4 /*yield*/, this.send(body)];
case 1: return [2 /*return*/, (_a.sent()).result];
}
});
});
};
AirGapNodeClient.prototype.getTransactionStatus = function (transactionHash) {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_getTransactionReceipt', [transactionHash]);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, response.result.status === '0x1' ? IAirGapTransaction_1.AirGapTransactionStatus.APPLIED : IAirGapTransaction_1.AirGapTransactionStatus.FAILED];
}
});
});
};
AirGapNodeClient.prototype.callBalanceOf = function (contractAddress, address) {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = this.balanceOfBody(contractAddress, address);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, new bignumber_1.BigNumber(response.result)];
}
});
});
};
AirGapNodeClient.prototype.callBalanceOfOnContracts = function (contractAddresses, address) {
return __awaiter(this, void 0, void 0, function () {
var bodies, responses, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
bodies = contractAddresses.map(function (contractAddress, index) { return _this.balanceOfBody(contractAddress, address, index); });
return [4 /*yield*/, this.batchSend(bodies)];
case 1:
responses = _a.sent();
result = {};
responses.forEach(function (response) {
var _a;
result[contractAddresses[response.id]] = new bignumber_1.BigNumber((_a = response.result, (_a !== null && _a !== void 0 ? _a : 0)));
});
return [2 /*return*/, result];
}
});
});
};
AirGapNodeClient.prototype.balanceOfBody = function (contractAddress, address, id) {
if (id === void 0) { id = 0; }
var data = new EthereumRPCDataBalanceOf(address);
return new EthereumRPCBody('eth_call', [{ to: contractAddress, data: data.abiEncoded() }, EthereumRPCBody.blockLatest], id);
};
AirGapNodeClient.prototype.estimateTransactionGas = function (fromAddress, toAddress, amount, data, gas) {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_estimateGas', [{ from: fromAddress, to: toAddress, gas: gas, value: amount, data: data }]);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, new bignumber_1.BigNumber(response.result)];
}
});
});
};
AirGapNodeClient.prototype.estimateTransferGas = function (contractAddress, fromAddress, toAddress, hexAmount) {
return __awaiter(this, void 0, void 0, function () {
var data, result;
return __generator(this, function (_a) {
data = new EthereumRPCDataTransfer(toAddress, hexAmount);
result = this.estimateTransactionGas(fromAddress, contractAddress, undefined, data.abiEncoded());
return [2 /*return*/, result];
});
});
};
AirGapNodeClient.prototype.getGasPrice = function () {
return __awaiter(this, void 0, void 0, function () {
var body, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
body = new EthereumRPCBody('eth_gasPrice', []);
return [4 /*yield*/, this.send(body)];
case 1:
response = _a.sent();
return [2 /*return*/, new bignumber_1.BigNumber(response.result)];
}
});
});
};
AirGapNodeClient.prototype.send = function (body) {
return __awaiter(this, void 0, void 0, function () {
var data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, index_1.default.post(this.baseURL, body.toRPCBody())];
case 1:
data = (_a.sent()).data;
if (data.error !== undefined) {
throw new Error(data.error.message);
}
return [2 /*return*/, data];
}
});
});
};
AirGapNodeClient.prototype.batchSend = function (bodies) {
return __awaiter(this, void 0, void 0, function () {
var data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, index_1.default.post(this.baseURL, JSON.stringify(bodies.map(function (body) { return body.toJSON(); })))];
case 1:
data = (_a.sent()).data;
return [2 /*return*/, data];
}
});
});
};
return AirGapNodeClient;
}(NodeClient_1.EthereumNodeClient));
exports.AirGapNodeClient = AirGapNodeClient;
//# sourceMappingURL=AirGapNodeClient.js.map