Skip to content

Commit

Permalink
Merge pull request #480 from arconnectio/development
Browse files Browse the repository at this point in the history
ArConnect BETA 1.18.3
  • Loading branch information
nicholaswma authored Sep 27, 2024
2 parents 61b28b3 + 9953150 commit e46c390
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 303 deletions.
22 changes: 13 additions & 9 deletions src/api/modules/sign_data_item/sign_data_item.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,22 @@ const background: ModuleFunction<number[]> = async (
)
) {
try {
const tags = dataItem?.tags || [];
const quantityTag = tags.find((tag) => tag.name === "Quantity");
const quantityTag = dataItem.tags?.find((tag) => tag.name === "Quantity");
if (quantityTag) {
const quantity = BigNumber(quantityTag.value).toFixed(
0,
BigNumber.ROUND_FLOOR
);
if (!isNaN(+quantity)) {
quantityTag.value = quantity;
const quantityBigNum = BigNumber(quantityTag.value);

// Ensure the quantity is a valid positive non-zero number (greater than 0)
if (!quantityBigNum.isPositive() || quantityBigNum.isZero()) {
throw new Error("INVALID_QUANTITY");
}

quantityTag.value = quantityBigNum.toFixed(0, BigNumber.ROUND_FLOOR);
}
} catch {}
} catch (e) {
if (e?.message === "INVALID_QUANTITY") {
throw new Error("Quantity must be a valid positive non-zero number.");
}
}
try {
await authenticate({
type: "signDataItem",
Expand Down
8 changes: 3 additions & 5 deletions src/components/popup/HistoryProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type PropsWithChildren, useEffect, useState } from "react";
import { getDecryptionKey, isExpired } from "~wallets/auth";
import { getDecryptionKey } from "~wallets/auth";
import { useLocation } from "wouter";
import {
type BackAction,
Expand Down Expand Up @@ -28,14 +28,12 @@ export default function HistoryProvider({ children }: PropsWithChildren<{}>) {
};

// redirect to unlock if decryiption
// key is not available or if the password
// has expired and needs to be reset
// key is not available
useEffect(() => {
(async () => {
const decryptionKey = await getDecryptionKey();
const expired = await isExpired();

if (!decryptionKey || expired) {
if (!decryptionKey) {
push("/unlock");
}
})();
Expand Down
53 changes: 33 additions & 20 deletions src/components/popup/home/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ export default function Balance() {
}

useEffect(() => {
if (parseFloat(balance.toString()) !== historicalBalance[0]) {
if (
balance.toNumber() !== historicalBalance[historicalBalance.length - 1]
) {
setLoading(true);
} else {
setLoading(false);
Expand Down Expand Up @@ -198,13 +200,19 @@ export default function Balance() {

async function balanceHistory(address: string, gateway: Gateway) {
const arweave = new Arweave(gateway);
let minHeight = 0;
try {
const { height } = await arweave.network.getInfo();
// blocks per day - 720
minHeight = height - 720 * 30;
} catch {}

// find txs coming in and going out
const inTxs = (
await gql(
`
query($recipient: String!) {
transactions(recipients: [$recipient], first: 100) {
query($recipient: String!, $minHeight: Int!) {
transactions(recipients: [$recipient], first: 100, bundledIn: null, block: {min: $minHeight}) {
edges {
node {
owner {
Expand All @@ -224,14 +232,15 @@ async function balanceHistory(address: string, gateway: Gateway) {
}
}
`,
{ recipient: address }
{ recipient: address, minHeight }
)
).data.transactions.edges;

const outTxs = (
await gql(
`
query($owner: String!) {
transactions(owners: [$owner], first: 100) {
query($owner: String!, $minHeight: Int!) {
transactions(owners: [$owner], first: 100, bundledIn: null, block: {min: $minHeight}) {
edges {
node {
owner {
Expand All @@ -251,38 +260,42 @@ async function balanceHistory(address: string, gateway: Gateway) {
}
}
`,
{ owner: address }
{ owner: address, minHeight }
)
).data.transactions.edges;

// sort txs
// Merge and sort transactions in descending order (newest first)
const txs = inTxs
.concat(outTxs)
.map((edge) => edge.node)
.filter((tx) => !!tx?.block?.timestamp)
.sort((a, b) => a.block.timestamp - b.block.timestamp);
.filter((tx) => !!tx?.block?.timestamp) // Filter out transactions without a timestamp
.sort((a, b) => b.block.timestamp - a.block.timestamp); // Sort by newest to oldest

// get initial balance
let balance = parseFloat(
// Get the current balance
let balance = BigNumber(
arweave.ar.winstonToAr(await arweave.wallets.getBalance(address))
);

const res = [balance];
// Initialize the result array with the current balance
const res = [balance.toNumber()];

// go back in time by tx and calculate
// historical balance
// Process transactions from newest to oldest, adjusting the balance
for (const tx of txs) {
balance -= parseFloat(tx.fee.ar);

if (tx.owner.address === address) {
balance -= parseFloat(tx.quantity.ar);
// Outgoing transaction: add back the transaction amount and fee (since we are reversing)
balance = balance.plus(tx.quantity.ar).plus(tx.fee.ar);
} else {
balance += parseFloat(tx.quantity.ar);
// Incoming transaction: subtract the amount received
balance = balance.minus(tx.quantity.ar);
}

res.push(balance);
// Push the balance at that point in time
res.push(balance.toNumber());
}

// Reverse the result array to have chronological order for the line chart (oldest to newest)
res.reverse();

return res;
}

Expand Down
9 changes: 7 additions & 2 deletions src/components/popup/home/Transactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
sortFn,
type ExtendedTransaction
} from "~lib/transactions";
import BigNumber from "bignumber.js";

export default function Transactions() {
const [transactions, fetchTransactions] = useState<ExtendedTransaction[]>([]);
Expand Down Expand Up @@ -62,8 +63,12 @@ export default function Transactions() {
)
);

const sent = await processTransactions(rawSent, "sent");
const received = await processTransactions(rawReceived, "received");
let sent = await processTransactions(rawSent, "sent");
sent = sent.filter((tx) => BigNumber(tx.node.quantity.ar).gt(0));
let received = await processTransactions(rawReceived, "received");
received = received.filter((tx) =>
BigNumber(tx.node.quantity.ar).gt(0)
);
const aoSent = await processTransactions(rawAoSent, "aoSent", true);
const aoReceived = await processTransactions(
rawAoReceived,
Expand Down
9 changes: 6 additions & 3 deletions src/lib/ao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,12 @@ export class AOProcess {
this.processId = processId;
this.ao = connect({
GRAPHQL_URL:
connectionConfig?.GATEWAY_URL ??
joinUrl({ url: defaultConfig.GATEWAY_URL, path: "graphql" }),
CU_URL: connectionConfig?.GATEWAY_URL ?? defaultConfig.CU_URL,
connectionConfig?.GRAPHQL_URL ??
joinUrl({
url: connectionConfig?.GATEWAY_URL ?? defaultConfig.GATEWAY_URL,
path: "graphql"
}),
CU_URL: connectionConfig?.CU_URL ?? defaultConfig.CU_URL,
MU_URL: connectionConfig?.MU_URL ?? defaultConfig.MU_URL,
GATEWAY_URL: connectionConfig?.GATEWAY_URL ?? defaultConfig.GATEWAY_URL
});
Expand Down
28 changes: 24 additions & 4 deletions src/notifications/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
combineAndSortTransactions,
processTransactions
} from "./utils";
import BigNumber from "bignumber.js";

export type RawTransaction = {
node: {
Expand Down Expand Up @@ -87,13 +88,15 @@ export async function notificationsHandler(alarmInfo?: Alarms.Alarm) {
query: !aoNotificationSetting.includes("allTxns")
? AR_RECEIVER_QUERY
: ALL_AR_RECEIVER_QUERY,
variables: { address }
variables: { address },
isAllTxns: aoNotificationSetting.includes("allTxns")
},
{
query: !aoNotificationSetting.includes("allTxns")
? AR_SENT_QUERY
: ALL_AR_SENT_QUERY,
variables: { address }
variables: { address },
isAllTxns: aoNotificationSetting.includes("allTxns")
}
]
);
Expand Down Expand Up @@ -181,15 +184,32 @@ const arNotificationsHandler = async (
address: string,
lastStoredHeight: number,
notificationSetting: boolean,
queriesConfig: { query: string; variables: Record<string, any> }[]
queriesConfig: {
query: string;
variables: Record<string, any>;
isAllTxns?: boolean;
}[]
): Promise<ArNotificationsHandlerReturnType> => {
try {
let transactionDiff = [];

const queries = queriesConfig.map((config) =>
gql(config.query, config.variables, suggestedGateways[1])
);
const responses = await Promise.all(queries);
let responses = await Promise.all(queries);
responses = responses.map((response, index) => {
if (
typeof queriesConfig[index].isAllTxns === "boolean" &&
!queriesConfig[index].isAllTxns
) {
response.data.transactions.edges =
response.data.transactions.edges.filter((edge) =>
BigNumber(edge.node.quantity.ar).gt(0)
);
}
return response;
});

const combinedTransactions = combineAndSortTransactions(responses);

const enrichedTransactions = processTransactions(
Expand Down
9 changes: 4 additions & 5 deletions src/notifications/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

export const AR_RECEIVER_QUERY = `
query ($address: String!) {
transactions(first: 10, recipients: [$address], tags: [{ name: "Type", values: ["Transfer"] }]) {
transactions(first: 10, recipients: [$address], bundledIn: null) {
edges {
cursor
node {
Expand All @@ -23,7 +22,7 @@ query ($address: String!) {
`;

export const AR_SENT_QUERY = `query ($address: String!) {
transactions(first: 10, owners: [$address], tags: [{ name: "Type", values: ["Transfer"] }]) {
transactions(first: 10, owners: [$address], bundledIn: null) {
edges {
cursor
node {
Expand Down Expand Up @@ -136,7 +135,7 @@ export const ALL_AR_SENT_QUERY = `query ($address: String!) {

export const AR_RECEIVER_QUERY_WITH_CURSOR = `
query ($address: String!, $after: String) {
transactions(first: 10, recipients: [$address], tags: [{ name: "Type", values: ["Transfer"] }], after: $after) {
transactions(first: 10, recipients: [$address], bundledIn: null, after: $after) {
pageInfo {
hasNextPage
}
Expand All @@ -160,7 +159,7 @@ query ($address: String!, $after: String) {

export const AR_SENT_QUERY_WITH_CURSOR = `
query ($address: String!, $after: String) {
transactions(first: 10, owners: [$address], tags: [{ name: "Type", values: ["Transfer"] }], after: $after) {
transactions(first: 10, owners: [$address], bundledIn: null, after: $after) {
pageInfo {
hasNextPage
}
Expand Down
18 changes: 5 additions & 13 deletions src/routes/popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import WalletHeader from "~components/popup/WalletHeader";
import NoBalance from "~components/popup/home/NoBalance";
import Balance from "~components/popup/home/Balance";
import { AnnouncementPopup } from "./announcement";
import { getDecryptionKey, isExpired } from "~wallets/auth";
import { getDecryptionKey } from "~wallets/auth";
import { useHistory } from "~utils/hash_router";
import {
trackEvent,
Expand Down Expand Up @@ -87,19 +87,11 @@ export default function Home() {
}, [activeAddress, assets, aoTokens]);

useEffect(() => {
// check if password is expired here
const checkExpiration = async () => {
const expired = await isExpired();
// delete expiration from storage here or in unlock page
if (expired) {
ExtensionStorage.remove("password_expires");
push("/unlock");
} else {
await trackEvent(EventType.LOGIN, {});
await trackPage(PageType.HOME);
}
const trackEventAndPage = async () => {
await trackEvent(EventType.LOGIN, {});
await trackPage(PageType.HOME);
};
checkExpiration();
trackEventAndPage();

// schedule import ao tokens
scheduleImportAoTokens();
Expand Down
10 changes: 3 additions & 7 deletions src/routes/popup/transaction/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ import { TempTransactionStorage } from "~utils/storage";
import { useContact } from "~contacts/hooks";
import { EventType, PageType, trackEvent, trackPage } from "~utils/analytics";
import BigNumber from "bignumber.js";
import { Token } from "ao-tokens";
import { fetchTokenByProcessId } from "~lib/transactions";
import type { TokenInfo } from "~tokens/aoTokens/ao";

// pull contacts and check if to address is in contacts

Expand Down Expand Up @@ -161,11 +159,9 @@ export default function Transaction({ id: rawId, gw, message }: Props) {
);

if (aoQuantity) {
let tokenInfo;
tokenInfo = await fetchTokenByProcessId(data.transaction.recipient);
if (!tokenInfo) {
tokenInfo = (await Token(data.transaction.recipient)).info;
}
const tokenInfo = await fetchTokenByProcessId(
data.transaction.recipient
);
if (tokenInfo) {
const amount = balanceToFractioned(aoQuantity.value, {
id: data.transaction.recipient,
Expand Down
8 changes: 6 additions & 2 deletions src/routes/popup/transaction/transactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
getFullMonthName,
getTransactionDescription
} from "~lib/transactions";
import BigNumber from "bignumber.js";

const defaultCursors = ["", "", "", ""];
const defaultHasNextPages = [true, true, true, true];
Expand Down Expand Up @@ -85,8 +86,8 @@ export default function Transactions() {
})
);

const sent = await processTransactions(rawSent, "sent");
const received = await processTransactions(rawReceived, "received");
let sent = await processTransactions(rawSent, "sent");
let received = await processTransactions(rawReceived, "received");
const aoSent = await processTransactions(rawAoSent, "aoSent", true);
const aoReceived = await processTransactions(
rawAoReceived,
Expand All @@ -100,6 +101,9 @@ export default function Transactions() {
)
);

sent = sent.filter((tx) => BigNumber(tx.node.quantity.ar).gt(0));
received = received.filter((tx) => BigNumber(tx.node.quantity.ar).gt(0));

setHasNextPages(
[rawReceived, rawSent, rawAoSent, rawAoReceived].map(
(result) =>
Expand Down
Loading

0 comments on commit e46c390

Please sign in to comment.