Skip to content

Commit

Permalink
Merge branch 'main' into feat/safari-support
Browse files Browse the repository at this point in the history
  • Loading branch information
kvhnuke committed Oct 2, 2023
2 parents 137aeb2 + e90f867 commit 5676d73
Show file tree
Hide file tree
Showing 40 changed files with 760 additions and 201 deletions.
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

1 comment on commit 5676d73

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.