@pgchain/blockchain-libs
Version:
PGWallet Blockchain Libs
279 lines • 13 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Provider = void 0;
const conflux_address_js_1 = require("@conflux-dev/conflux-address-js");
const abi_1 = require("@ethersproject/abi");
const bytes_1 = require("@ethersproject/bytes");
const keccak256_1 = require("@ethersproject/keccak256");
const js_sdk_1 = __importDefault(require("@onekeyfe/js-sdk"));
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const ethUtil = __importStar(require("ethereumjs-util"));
// @ts-ignore: has no exported member 'PersonalMessage'
const js_conflux_sdk_1 = require("js-conflux-sdk");
const bignumber_plus_1 = require("../../../basic/bignumber-plus");
const precondtion_1 = require("../../../basic/precondtion");
const abc_1 = require("../../abc");
const message_1 = require("../eth/sdk/message");
const conflux_1 = require("./conflux");
function hashCfxMessage(typedMessage) {
const { type, message } = typedMessage;
switch (type) {
case undefined:
case message_1.MessageTypes.ETH_SIGN:
return new js_conflux_sdk_1.Message(message).hash;
case message_1.MessageTypes.PERSONAL_SIGN:
return new js_conflux_sdk_1.PersonalMessage(message).hash;
// TODO: cip-23 depends on @findeth/abi which makes builds fail on android
// import { getMessage } from 'cip-23';
// case MessageTypes.TYPE_DATA_V3:
// case MessageTypes.TYPE_DATA_V4:
// return keccak256(getMessage(JSON.parse(message)));
default:
throw new Error(`Invalid messageType: ${type}`);
}
}
class Provider extends abc_1.BaseProvider {
get conflux() {
return this.clientSelector((i) => i instanceof conflux_1.Conflux);
}
internalPubkeyToAddress(pubkey) {
const ethAddress = this.ethAddressToCfxAddress((0, keccak256_1.keccak256)(pubkey).slice(-40));
const networkID = parseInt(this.chainInfo.implOptions.chainId);
return (0, conflux_address_js_1.encode)(ethAddress, networkID);
}
verifyAddress(address) {
const isValid = (0, conflux_address_js_1.isValidCfxAddress)(address);
return Promise.resolve({
normalizedAddress: isValid ? address.toLowerCase() : undefined,
displayAddress: isValid ? address.toLowerCase() : undefined,
isValid,
});
}
async pubkeyToAddress(verifier, encoding) {
const uncompressPubKey = await verifier.getPubkey(false);
return this.internalPubkeyToAddress(uncompressPubKey.slice(1));
}
/**
* transform the eth address to cfx format address
* @param address the eth format address {string}
* @returns the cfx format address {string}
*/
ethAddressToCfxAddress(address) {
return `0x1${address.toLowerCase().slice(1)}`;
}
async buildUnsignedTx(unsignedTx) {
const input = unsignedTx.inputs[0];
const output = unsignedTx.outputs[0];
const payload = unsignedTx.payload || {};
let nonce = unsignedTx.nonce;
let feeLimit = unsignedTx.feeLimit;
if (input && output) {
const fromAddress = input.address;
const tokenAddress = output.tokenAddress;
let toAddress = output.address;
let value = (0, bignumber_plus_1.toBigIntHex)(output.value);
let data;
if (tokenAddress) {
toAddress = '0x' + (0, conflux_address_js_1.decode)(toAddress).hexAddress.toString('hex');
data =
'0xa9059cbb' +
abi_1.defaultAbiCoder
.encode(['address', 'uint256'], [toAddress, value])
.slice(2); // method_selector(transfer) + byte32_pad(address) + byte32_pad(value)
value = '0x0';
toAddress = tokenAddress;
}
else {
data = payload.data;
}
if (typeof data === 'string' && data) {
payload.data = data;
}
if (!feeLimit) {
const estimatedGasLimit = await (await this.conflux).estimateGasLimit(fromAddress, toAddress, value, data);
const estimatedGasLimitBN = (0, bignumber_plus_1.fromBigIntHex)(estimatedGasLimit);
const multiplier = this.chainInfo.implOptions['contract_gaslimit_multiplier'] || 1.2;
feeLimit =
tokenAddress || (await (await this.conflux).isContract(toAddress))
? estimatedGasLimitBN.multipliedBy(multiplier).integerValue()
: estimatedGasLimitBN;
}
if (typeof nonce !== 'number' || nonce < 0) {
const [addressInfo] = await (await this.conflux).getAddresses([fromAddress]);
nonce = addressInfo === null || addressInfo === void 0 ? void 0 : addressInfo.nonce;
}
const [_, storageLimit] = await (await this.conflux).estimateGasAndCollateral(fromAddress, toAddress, value, data);
const epochHeight = await (await this.conflux).getEpochNumber();
payload.storageLimit = (0, bignumber_plus_1.fromBigIntHex)(storageLimit);
payload.epochHeight = epochHeight;
}
const feePricePerUnit = unsignedTx.feePricePerUnit ||
(await (await this.conflux).getFeePricePerUnit()).normal.price;
feeLimit = feeLimit || new bignumber_js_1.default(21000);
return Object.assign(unsignedTx, {
inputs: input ? [input] : [],
outputs: output ? [output] : [],
nonce,
feeLimit,
feePricePerUnit,
payload,
});
}
async signTransaction(unsignedTx, signers) {
var _a;
const fromAddress = (_a = unsignedTx.inputs[0]) === null || _a === void 0 ? void 0 : _a.address;
(0, precondtion_1.check)(fromAddress && signers[fromAddress], 'Signer not found');
const params = this.buildCFXUnSignedTx(unsignedTx);
const unSignedTx = new js_conflux_sdk_1.Transaction(params);
const digest = (0, keccak256_1.keccak256)(unSignedTx.encode(false));
const [sig, recoveryParam] = await signers[fromAddress].sign(Buffer.from(digest.slice(2), 'hex'));
const [r, s] = [sig.slice(0, 32), sig.slice(32)];
const SignedTx = new js_conflux_sdk_1.Transaction({
...params,
r: (0, bytes_1.hexZeroPad)('0x' + r.toString('hex'), 32),
s: (0, bytes_1.hexZeroPad)('0x' + s.toString('hex'), 32),
v: recoveryParam,
});
const rawTx = SignedTx.serialize();
const txid = (0, keccak256_1.keccak256)(rawTx);
return { txid, rawTx };
}
buildCFXUnSignedTx(unsignedTx) {
var _a;
const output = unsignedTx.outputs[0];
const isERC20Transfer = !!output.tokenAddress;
const toAddress = isERC20Transfer ? output.tokenAddress : output.address;
const value = isERC20Transfer ? '0x0' : output.value;
return {
to: toAddress,
value,
gas: (0, precondtion_1.checkIsDefined)(unsignedTx.feeLimit),
gasPrice: (0, precondtion_1.checkIsDefined)(unsignedTx.feePricePerUnit),
storageLimit: unsignedTx.payload.storageLimit,
epochHeight: unsignedTx.payload.epochHeight,
nonce: (0, precondtion_1.checkIsDefined)(unsignedTx.nonce),
data: ((_a = unsignedTx.payload) === null || _a === void 0 ? void 0 : _a.data) || '0x',
chainId: parseInt((0, precondtion_1.checkIsDefined)(this.chainInfo.implOptions.chainId)),
};
}
async hardwareGetXpubs(paths, showOnDevice) {
const resp = await this.wrapHardwareCall(() => js_sdk_1.default.confluxGetPublicKey({
bundle: paths.map((path) => ({ path, showOnTrezor: showOnDevice })),
}));
return resp.map((i) => ({
path: i.serializedPath,
xpub: i.xpub,
}));
}
async hardwareGetAddress(path, showOnDevice, addressToVerify) {
const params = {
path,
showOnTrezor: showOnDevice,
chain_id: Number((0, precondtion_1.checkIsDefined)(this.chainInfo.implOptions.chainId)),
};
if (typeof addressToVerify === 'string') {
Object.assign(params, {
address: addressToVerify,
});
}
const { address } = await this.wrapHardwareCall(() => js_sdk_1.default.confluxGetAddress(params));
return address;
}
async hardwareSignTransaction(unsignedTx, signers) {
const { inputs: [{ address: fromAddress }], } = unsignedTx;
const signer = signers[fromAddress];
(0, precondtion_1.check)(signer, 'Signer not found');
const tx = this.buildCFXUnSignedTx(unsignedTx);
const { r, s, v } = await this.wrapHardwareCall(() => js_sdk_1.default.confluxSignTransaction({
path: signer,
transaction: {
to: tx.to,
value: tx.value,
gasPrice: tx.gasPrice,
gasLimit: tx.gasLimit,
nonce: ethUtil.addHexPrefix(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
ethUtil.padToEven(tx.nonce.toString(16))),
epochHeight: tx.epochHeight,
storageLimit: tx.storageLimit,
chainId: tx.chainId,
data: tx.data,
},
}));
const SignedTx = new js_conflux_sdk_1.Transaction({
...tx,
r: ethUtil.addHexPrefix(r),
s: ethUtil.addHexPrefix(s),
v: Number(v),
});
const rawTx = SignedTx.serialize();
const txid = (0, keccak256_1.keccak256)(rawTx);
return { txid, rawTx };
}
async hardwareSignMessage(message, signer) {
const { type: messageType, message: strMessage } = message;
switch (messageType) {
case message_1.MessageTypes.PERSONAL_SIGN: {
const { signature } = await this.wrapHardwareCall(() => js_sdk_1.default.confluxSignMessage({
path: signer,
message: strMessage,
}));
return ethUtil.addHexPrefix(signature);
}
case message_1.MessageTypes.TYPE_DATA_V3:
case message_1.MessageTypes.TYPE_DATA_V4: {
const { signature } = await this.wrapHardwareCall(() => js_sdk_1.default.ConfluxSignMessageCIP23({
path: signer,
data: JSON.parse(strMessage),
}));
return ethUtil.addHexPrefix(signature);
}
}
throw new Error(`Not supported`);
}
async hardwareVerifyMessage(address, message, signature) {
const { type: messageType, message: strMessage } = message;
if (messageType === message_1.MessageTypes.PERSONAL_SIGN) {
const { message: resp } = await this.wrapHardwareCall(() => js_sdk_1.default.confluxVerifyMessage({
address,
message: strMessage,
signature,
}));
return resp === 'Message verified';
}
throw new Error('Not supported');
}
async signMessage(message, signer, address) {
return js_conflux_sdk_1.Message.sign('0x' + (await signer.getPrvkey()).toString('hex'), hashCfxMessage(message));
}
async verifyMessage(address, message, signature) {
const messageHash = hashCfxMessage(message);
// Message.recover returns a string with 0x prefix.
const publicKey = js_conflux_sdk_1.Message.recover(signature, messageHash).slice(2);
return Promise.resolve(address === this.internalPubkeyToAddress(Buffer.from(publicKey, 'hex')));
}
}
exports.Provider = Provider;
//# sourceMappingURL=provider.js.map