@okxweb3/coin-ethereum
Version:
An Ethereum SDK for building Web3 wallets and applications.
391 lines • 15.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EthWallet = void 0;
const coin_base_1 = require("@okxweb3/coin-base");
const coin_base_2 = require("@okxweb3/coin-base");
const coin_base_3 = require("@okxweb3/coin-base");
const eth = __importStar(require("./index"));
const ethereumjs_util_1 = require("./lib/sdk/ethereumjs-util");
const index_1 = require("./index");
const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb';
class EthWallet extends coin_base_1.BaseWallet {
async getDerivedPath(param) {
return `m/44'/60'/0'/0/${param.index}`;
}
async getNewAddress(param) {
let pri = param.privateKey;
let ok = eth.validPrivateKey(pri);
if (!ok) {
throw new Error('invalid key');
}
try {
const privateKey = coin_base_2.base.fromHex(pri.toLowerCase());
(0, coin_base_1.assertBufferLength)(privateKey, 32);
return Promise.resolve(eth.getNewAddress(pri.toLowerCase()));
}
catch (e) { }
return Promise.reject(coin_base_1.NewAddressError);
}
async validPrivateKey(param) {
let isValid = eth.validPrivateKey(param.privateKey);
const data = {
isValid: isValid,
privateKey: param.privateKey,
};
return Promise.resolve(data);
}
async validAddress(param) {
try {
return Promise.resolve(eth.validAddress(param.address));
}
catch (e) {
return Promise.resolve({
isValid: false,
});
}
}
convert2HexString(data) {
let n;
if (coin_base_2.BigNumber.isBigNumber(data)) {
n = data;
}
else {
n = new coin_base_2.BigNumber(data);
}
return coin_base_2.base.toBigIntHex(n);
}
convert2TxParam(data) {
const param = {
to: data.to,
value: this.convert2HexString(data.value || 0),
nonce: this.convert2HexString(data.nonce),
contractAddress: data.contractAddress,
gasPrice: this.convert2HexString(data.gasPrice || 0),
gasLimit: this.convert2HexString(data.gasLimit || 0),
data: data.data,
chainId: this.convert2HexString(data.chainId || 1),
type: data.type || 0,
maxPriorityFeePerGas: this.convert2HexString(data.maxPriorityFeePerGas || 0),
maxFeePerGas: this.convert2HexString(data.maxFeePerGas || 0),
authorizationList: data.authorizationList || [],
useValue: data.useValue || false,
};
return param;
}
async signTransaction(param) {
try {
const privateKey = param.privateKey;
if (privateKey) {
(0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(privateKey), 32);
}
const txParams = this.convert2TxParam(param.data);
if (txParams.to) {
const validation = await this.validAddress({
address: txParams.to,
});
if (!validation.isValid) {
return Promise.reject(coin_base_1.ValidAddressError);
}
}
if (txParams.contractAddress) {
const validation = await this.validAddress({
address: txParams.contractAddress,
});
if (!validation.isValid) {
return Promise.reject(coin_base_1.ValidAddressError);
}
}
const chainId = txParams.chainId;
const nonce = txParams.nonce;
const type = txParams.type;
if (type === 0 || type === 1) {
const gasPrice = txParams.gasPrice;
const tokenAddress = txParams.contractAddress;
let toAddress = txParams.to;
let value = txParams.value;
let data;
if (tokenAddress) {
data =
TOKEN_TRANSFER_FUNCTION_SIGNATURE +
Array.prototype.map
.call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2))
.join('');
if (!txParams.useValue) {
value = '0x0';
}
toAddress = tokenAddress;
}
else {
data = txParams.data;
}
const txData = {
nonce: nonce,
gasPrice: gasPrice,
gasLimit: txParams.gasLimit,
to: toAddress,
value: value,
data: data,
chainId: chainId,
type: type,
};
return Promise.resolve(eth.signTransaction(privateKey, txData));
}
else if (type === 2) {
const tokenAddress = txParams.contractAddress;
let toAddress = txParams.to;
let value = txParams.value;
let data;
if (tokenAddress) {
data =
TOKEN_TRANSFER_FUNCTION_SIGNATURE +
Array.prototype.map
.call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2))
.join('');
value = '0x0';
toAddress = tokenAddress;
}
else {
data = txParams.data;
}
const txData = {
nonce: nonce,
gasLimit: txParams.gasLimit,
to: toAddress,
value: value,
data: data,
chainId: chainId,
type: type,
maxPriorityFeePerGas: txParams.maxPriorityFeePerGas,
maxFeePerGas: txParams.maxFeePerGas,
};
return Promise.resolve(eth.signTransaction(privateKey, txData));
}
else if (type === 4) {
const tokenAddress = txParams.contractAddress;
let toAddress = txParams.to;
let value = txParams.value;
let data;
if (tokenAddress) {
data =
TOKEN_TRANSFER_FUNCTION_SIGNATURE +
Array.prototype.map
.call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2))
.join('');
value = '0x0';
toAddress = tokenAddress;
}
else {
data = txParams.data;
}
const txData = {
nonce: nonce,
gasLimit: txParams.gasLimit,
to: toAddress,
value: value,
data: data,
chainId: chainId,
type: type,
maxPriorityFeePerGas: txParams.maxPriorityFeePerGas,
maxFeePerGas: txParams.maxFeePerGas,
authorizationList: txParams.authorizationList,
};
return Promise.resolve(eth.signTransaction(privateKey, txData));
}
return Promise.reject(coin_base_1.SignTxError);
}
catch (e) {
return Promise.reject(coin_base_1.SignTxError);
}
}
async signAuthorizationListItem(param) {
if (!param.privateKey) {
throw Error('privateKey is invalid');
}
const privateKey = coin_base_2.base.fromHex(param.privateKey);
(0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(param.privateKey), 32);
const { chainId, nonce, address } = param.data;
const chainIdBytes = eth.unpadBytes(eth.hexToBytes(chainId));
const nonceBytes = nonce !== undefined
? eth.unpadBytes(eth.hexToBytes(nonce))
: new Uint8Array();
const addressBytes = eth.hexToBytes(address);
const rlpdMsg = ethereumjs_util_1.rlp.encode([chainIdBytes, addressBytes, nonceBytes]);
const msgToSign = eth.keccak256((0, ethereumjs_util_1.concatBytes)(new Uint8Array([5]), rlpdMsg));
const signed = eth.ecdsaSign(msgToSign, privateKey);
const auth = {
chainId: (0, index_1.bytesToHex)(chainIdBytes),
address: address,
nonce: (0, index_1.bytesToHex)(nonceBytes),
yParity: signed.v - 27 === 0 ? '0x' : '0x1',
r: coin_base_2.base.toHex((0, index_1.unpadBuffer)(signed.r), true),
s: coin_base_2.base.toHex((0, index_1.unpadBuffer)(signed.s), true),
};
return auth;
}
async signAuthorizationListItemForRPC(param) {
const auth = await this.signAuthorizationListItem(param);
return this.toRpcAuth(auth);
}
toRpcAuth(auth) {
const keys = ['chainId', 'nonce', 'yParity', 'r', 's'];
const ret = { ...auth };
for (const key of keys) {
ret[key] = this.toRpcHex(ret[key]);
}
return ret;
}
toRpcHex(hex) {
const body = hex.slice(2);
const trimmedBody = body.replace(/^0+/, '') || '0';
return '0x' + trimmedBody;
}
async signMessage(param) {
if (!param.privateKey) {
return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: cannot be empty`);
}
return this.signMessage0(param);
}
async signMessage0(param) {
let privateKey;
if (param.privateKey) {
try {
(0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(param.privateKey), 32);
}
catch (e) {
return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: ${e.message}`);
}
privateKey = coin_base_2.base.fromHex(param.privateKey);
}
const data = param.data;
const t = data.type;
const result = eth.signMessage(t, data.message, privateKey);
return Promise.resolve(result);
}
async verifyMessage(param) {
const d = param.data;
const r = await this.ecRecover(d, param.signature);
const address = param.address || '';
return Promise.resolve(address.toLowerCase() === r.toLowerCase());
}
async ecRecover(message, signature) {
const t = message.type;
const publicKey = eth.verifyMessage(t, message.message, coin_base_2.base.fromHex(signature));
const address = coin_base_2.base.toHex(eth.publicToAddress(publicKey), true);
return Promise.resolve(address);
}
async encrypt(publicKey, data, version) {
return Promise.resolve(eth.sigUtil.encrypt({
publicKey: publicKey,
data: data,
version: version,
}));
}
async decrypt(encryptedData, privateKey) {
return Promise.resolve(eth.sigUtil.decrypt({
encryptedData: encryptedData,
privateKey: coin_base_2.base.stripHexPrefix(privateKey),
}));
}
async getEncryptionPublicKey(privateKey) {
return Promise.resolve(eth.sigUtil.getEncryptionPublicKey(coin_base_2.base.stripHexPrefix(privateKey)));
}
getAddressByPublicKey(param) {
return Promise.resolve(coin_base_2.base.toHex(eth.publicToAddress(coin_base_2.base.fromHex(param.publicKey), true), true));
}
async getMPCRawTransaction(param) {
try {
const mpcRaw = await this.signTransaction(param);
return Promise.resolve({
raw: mpcRaw.raw,
hash: mpcRaw.hash,
});
}
catch (e) {
return Promise.reject(coin_base_1.GetMpcRawTransactionError);
}
}
async getMPCTransaction(param) {
try {
const signedTx = eth.getMPCTransaction(param.raw, param.sigs, param.publicKey);
return Promise.resolve(signedTx);
}
catch (e) {
return Promise.reject(coin_base_1.GetMpcTransactionError);
}
}
async getMPCRawMessage(param) {
try {
const msgHash = await this.signMessage0(param);
return Promise.resolve({ hash: msgHash });
}
catch (e) {
return Promise.reject(coin_base_1.GetMpcRawTransactionError);
}
}
async getMPCSignedMessage(param) {
try {
return Promise.resolve(eth.getMPCSignedMessage(param.hash, param.sigs, param.publicKey));
}
catch (e) {
return Promise.reject(coin_base_1.GetMpcTransactionError);
}
}
async getHardWareRawTransaction(param) {
try {
const rawTx = await this.signTransaction(param);
return Promise.resolve(rawTx.serializeRaw);
}
catch (e) {
return Promise.reject(coin_base_1.GetHardwareRawTransactionError);
}
}
async getHardWareSignedTransaction(param) {
try {
return eth.getSignedTransaction(param.raw, param.r, param.s, param.v);
}
catch (e) {
return Promise.reject(coin_base_1.GetHardwareSignedTransactionError);
}
}
async calcTxHash(param) {
const serializedData = coin_base_2.base.fromHex(param.data);
const signedTx = eth.TransactionFactory.fromSerializedData(serializedData);
return Promise.resolve(coin_base_2.base.toHex(signedTx.hash(), true));
}
async validSignedTransaction(param) {
try {
const chainId = param.data ? param.data.chainId : undefined;
const publicKey = param.data ? param.data.publicKey : undefined;
const ret = eth.validSignedTransaction(param.tx, chainId, publicKey);
return Promise.resolve((0, coin_base_1.jsonStringifyUniform)(ret));
}
catch (e) {
return Promise.reject(coin_base_1.validSignedTransactionError);
}
}
}
exports.EthWallet = EthWallet;
//# sourceMappingURL=EthWallet.js.map