Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release: v1.28.0 #352

Merged
merged 14 commits into from
Oct 2, 2023
2 changes: 1 addition & 1 deletion packages/extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@enkryptcom/extension",
"version": "1.27.0",
"version": "1.28.0",
"private": true,
"scripts": {
"zip": "cd dist; zip -r release.zip *;",
Expand Down
10 changes: 10 additions & 0 deletions packages/extension/src/libs/keyring/public-keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ class PublicKeyRing {
walletType: WalletType.mnemonic,
isHardware: false,
};
allKeys["ltc1qccf4af6j3xm9v3r6ujt7dlmvazywzq82hnuwgx"] = {
address: "ltc1qccf4af6j3xm9v3r6ujt7dlmvazywzq82hnuwgx",
basePath: "m/49'/2'/0'/1",
name: "fake ltc account #4",
pathIndex: 0,
publicKey: "0x0",
signerType: SignerType.secp256k1btc,
walletType: WalletType.mnemonic,
isHardware: false,
};
}
return allKeys;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import haskoinHandler from "./providers/haskoin";

export { haskoinHandler };
import ssHandler from "./providers/ss";
export { haskoinHandler, ssHandler };
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export default async (
if (relevantOut) {
toAddress = relevantOut.address;
value = relevantOut.value;
} else {
toAddress = tx.outputs[0].address;
value = Number(tx.outputs[0].value);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import MarketData from "@/libs/market-data";
import { SSTxType } from "@/providers/bitcoin/types";
import {
Activity,
ActivityStatus,
ActivityType,
BTCRawInfo,
} from "@/types/activity";
import { BaseNetwork } from "@/types/base-network";
export default async (
network: BaseNetwork,
pubkey: string
): Promise<Activity[]> => {
return fetch(
`${network.node}/api/v1/account/${network.displayAddress(
pubkey
)}/txs?pageSize=40`
)
.then((res) => res.json())
.then(async (txs: { txs: SSTxType[] }) => {
if ((txs as any).message) return [];
let tokenPrice = "0";
if (network.coingeckoID) {
const marketData = new MarketData();
await marketData
.getTokenPrice(network.coingeckoID)
.then((mdata) => (tokenPrice = mdata || "0"));
}

const address = network.displayAddress(pubkey);
const cleanedTxs = txs.txs.map((tx) => {
return {
...tx,
vin: tx.vin.filter((vi) => vi.addresses),
vout: tx.vout.filter((vo) => vo.addresses),
};
});
return cleanedTxs.map((tx) => {
const isIncoming = !tx.vin.find((i) => i.addresses![0] === address);
console.log(isIncoming, tx.vin, tx.vout, address);
let toAddress = "";
let value = 0;

if (isIncoming) {
const relevantOut = tx.vout.find(
(tx) => tx.addresses![0] === address
);
if (relevantOut) {
toAddress = relevantOut.addresses![0];
value = Number(relevantOut.value);
}
} else {
const relevantOut = tx.vout.find(
(tx) => tx.addresses![0] !== address
);
if (relevantOut) {
toAddress = relevantOut.addresses![0];
value = Number(relevantOut.value);
} else {
toAddress = tx.vout[0].addresses![0];
value = Number(tx.vout[0].value);
}
}

const rawInfo: BTCRawInfo = {
blockNumber: tx.blockHeight!,
fee: Number(tx.fee),
inputs: tx.vin.map((input) => ({
address: input.addresses![0],
value: Number(input.value),
})),
outputs: tx.vout.map((output) => ({
address: output.addresses![0],
value: Number(output.value),
})),
transactionHash: tx.txid,
timestamp: tx.timestamp * 1000,
};
const act: Activity = {
from: tx.vin[0].addresses![0],
isIncoming,
network: network.name,
status:
tx.blockHeight > 0
? ActivityStatus.success
: ActivityStatus.pending,
timestamp: tx.timestamp * 1000,
to: toAddress,
token: {
decimals: network.decimals,
icon: network.icon,
name: network.name_long,
symbol: network.currencyName,
coingeckoID: network.coingeckoID,
price: tokenPrice,
},
transactionHash: tx.txid,
type: ActivityType.transaction,
value: value.toString(),
rawInfo: rawInfo,
};
return act;
});
})
.catch(() => {
return [];
});
};
123 changes: 123 additions & 0 deletions packages/extension/src/providers/bitcoin/libs/api-ss.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { BTCRawInfo } from "@/types/activity";
import { ProviderAPIInterface } from "@/types/provider";
import {
BitcoinNetworkInfo,
HaskoinUnspentType,
SSTxType,
SSUnspentType,
} from "../types";
import { toBN } from "web3-utils";
import cacheFetch from "@/libs/cache-fetch";
import { getAddress as getBitcoinAddress } from "../types/bitcoin-network";

class API implements ProviderAPIInterface {
node: string;
networkInfo: BitcoinNetworkInfo;

constructor(node: string, networkInfo: BitcoinNetworkInfo) {
this.node = node;
this.networkInfo = networkInfo;
}

public get api() {
return this;
}
private getAddress(pubkey: string) {
return getBitcoinAddress(pubkey, this.networkInfo);
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async init(): Promise<void> {}
async getTransactionStatus(hash: string): Promise<BTCRawInfo | null> {
return fetch(`${this.node}/api/v1/tx/${hash}`)
.then((res) => res.json())
.then((tx: SSTxType) => {
if ((tx as any).message) return null;
if (tx.blockHeight < 0) return null;
const rawInfo: BTCRawInfo = {
blockNumber: tx.blockHeight,
fee: Number(tx.fee),
inputs: tx.vin
.filter((t) => t.addresses && t.addresses.length)
.map((input) => ({
address: input.addresses![0],
value: Number(input.value),
})),
outputs: tx.vout
.filter((t) => t.addresses && t.addresses.length)
.map((output) => ({
address: output.addresses![0],
value: Number(output.value),
})),
transactionHash: tx.txid,
timestamp: tx.timestamp * 1000,
};
return rawInfo;
});
}
async getBalance(pubkey: string): Promise<string> {
const address = pubkey.length < 64 ? pubkey : this.getAddress(pubkey);
return fetch(`${this.node}/api/v1/account/${address}`)
.then((res) => res.json())
.then((balance: { balance: string; unconfirmedBalance: string }) => {
if ((balance as any).message) return "0";
return toBN(balance.balance)
.add(toBN(balance.unconfirmedBalance))
.toString();
});
}
async broadcastTx(rawtx: string): Promise<boolean> {
return fetch(`${this.node}/api/v1/send`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ hex: rawtx }),
})
.then((res) => res.json())
.then((response) => {
if (response.error) {
return Promise.reject(response.message);
}
return true;
});
}
async SSToHaskoinUTXOs(
SSUTXOs: SSUnspentType[],
address: string
): Promise<HaskoinUnspentType[]> {
const ret: HaskoinUnspentType[] = [];
for (const utx of SSUTXOs) {
const res = (await cacheFetch({
url: `${this.node}/api/v1/tx/${utx.txid}`,
})) as SSTxType;
ret.push({
address,
block: {
height: utx.height,
position: 0,
},
index: utx.vout,
pkscript: res.vout[utx.vout].scriptPubKey.hex,
txid: utx.txid,
value: Number(utx.value),
raw: res.hex,
});
}
ret.sort((a, b) => {
return a.value - b.value;
});
return ret;
}

async getUTXOs(pubkey: string): Promise<HaskoinUnspentType[]> {
const address = pubkey.length < 64 ? pubkey : this.getAddress(pubkey);
return fetch(`${this.node}/api/v1/account/${address}/utxos`)
.then((res) => res.json())
.then((utxos: SSUnspentType[]) => {
if ((utxos as any).message || !utxos.length) return [];
return this.SSToHaskoinUTXOs(utxos, address);
});
}
}
export default API;
9 changes: 2 additions & 7 deletions packages/extension/src/providers/bitcoin/libs/api.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { BTCRawInfo } from "@/types/activity";
import { ProviderAPIInterface } from "@/types/provider";
import { hexToBuffer } from "@enkryptcom/utils";
import {
BitcoinNetworkInfo,
HaskoinBalanceType,
HaskoinTxType,
HaskoinUnspentType,
} from "../types";
import { payments } from "bitcoinjs-lib";
import { toBN } from "web3-utils";
import { getAddress as getBitcoinAddress } from "../types/bitcoin-network";

class API implements ProviderAPIInterface {
node: string;
Expand All @@ -23,11 +22,7 @@ class API implements ProviderAPIInterface {
return this;
}
private getAddress(pubkey: string) {
const { address } = payments.p2wpkh({
pubkey: hexToBuffer(pubkey),
network: this.networkInfo,
});
return address as string;
return getBitcoinAddress(pubkey, this.networkInfo);
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async init(): Promise<void> {}
Expand Down
33 changes: 33 additions & 0 deletions packages/extension/src/providers/bitcoin/libs/ss-fee-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { GasPriceTypes } from "@/providers/common/types";

interface FeeType {
fast: {
satsPerKiloByte: number;
};
average: {
satsPerKiloByte: number;
};
slow: {
satsPerKiloByte: number;
};
}
const SSFeeHandler = async (
url: string
): Promise<Record<GasPriceTypes, number>> => {
return fetch(url)
.then((res) => res.json())
.then((json: FeeType) => {
if (json.fast.satsPerKiloByte < 0)
json.fast.satsPerKiloByte = json.average.satsPerKiloByte;
return {
[GasPriceTypes.FASTEST]:
Math.ceil(json.fast.satsPerKiloByte / 1024) + 5,
[GasPriceTypes.FAST]: Math.ceil(json.fast.satsPerKiloByte / 1024) + 3,
[GasPriceTypes.REGULAR]:
Math.ceil(json.average.satsPerKiloByte / 1024) + 2,
[GasPriceTypes.ECONOMY]: Math.ceil(json.slow.satsPerKiloByte / 1024),
};
});
};

export default SSFeeHandler;
25 changes: 23 additions & 2 deletions packages/extension/src/providers/bitcoin/libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BitcoinNetworkInfo } from "../types";
import { BitcoinNetworkInfo, HaskoinUnspentType } from "../types";
import { address as BTCAddress } from "bitcoinjs-lib";
import { GasPriceTypes } from "@/providers/common/types";
import { fromBase } from "@enkryptcom/utils";
import BigNumber from "bignumber.js";
import { BitcoinNetwork } from "../types/bitcoin-network";
import { BTCTxInfo } from "../ui/types";

const isAddress = (address: string, network: BitcoinNetworkInfo): boolean => {
try {
Expand All @@ -13,6 +14,26 @@ const isAddress = (address: string, network: BitcoinNetworkInfo): boolean => {
return false;
}
};

const getTxInfo = (utxos: HaskoinUnspentType[]): BTCTxInfo => {
const txInfo: BTCTxInfo = {
inputs: [],
outputs: [],
};
utxos.forEach((u) => {
txInfo.inputs.push({
hash: u.txid,
index: u.index,
raw: u.raw,
witnessUtxo: {
script: u.pkscript,
value: u.value,
},
});
});
return txInfo;
};

const getGasCostValues = async (
network: BitcoinNetwork,
byteSize: number,
Expand Down Expand Up @@ -66,4 +87,4 @@ const getGasCostValues = async (
};
return gasCostValues;
};
export { isAddress, getGasCostValues };
export { isAddress, getGasCostValues, getTxInfo };
Loading
Loading