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

ArConnect 1.20.1 #532

Merged
merged 14 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,7 @@
"description": "Not connected indicator"
},
"not_connected_text": {
"message": "\"Connect / Disconnect\" is an indicator for when your ArConnect wallet is connected to an Arweave or AO application. For regular use like sending, receiving, checking balances, etc., ArConnect will always show disconnected.",
"message": "\"Connect / Disconnect\" is a label for when your ArConnect wallet is connected to an Arweave or AO dapp. For regular use like sending, receiving, checking balances, etc., ArConnect will always show disconnected.",
"description": "Not connected indicator explainer"
},
"disconnect": {
Expand Down Expand Up @@ -2009,11 +2009,11 @@
"description": "Popup description about ao token transfer learn more"
},
"ao_degraded": {
"message": "Unable to connect to AO Token Process",
"message": "Token balance error",
"description": "ao degraded title text"
},
"ao_degraded_description": {
"message": "AO balance will be available when <br/>network issues are resolved.",
"message": "Oops, ArConnect is unable to fetch your token balance. Please try again later.",
"description": "ao degraded description text"
},
"network_issue": {
Expand Down
4 changes: 2 additions & 2 deletions assets/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1999,11 +1999,11 @@
"description": "Popup description about ao token transfer learn more"
},
"ao_degraded": {
"message": "无法连接到 AO 令牌进程",
"message": "代币余额错误",
"description": "ao degraded title text"
},
"ao_degraded_description": {
"message": "网络问题解决后,AO 余额将可用。",
"message": "ArConnect 无法获取您的代币余额。这只是一个用户界面问题。请稍后重试。",
"description": "ao degraded description text"
},
"network_issue": {
Expand Down
37 changes: 13 additions & 24 deletions src/components/popup/Token.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
formatFiatBalance,
formatTokenBalance,
balanceToFractioned
} from "~tokens/currency";
import { formatFiatBalance, balanceToFractioned } from "~tokens/currency";
import {
type MouseEventHandler,
useEffect,
Expand All @@ -23,8 +19,6 @@ import * as viewblock from "~lib/viewblock";
import Squircle from "~components/Squircle";
import useSetting from "~settings/hook";
import styled from "styled-components";
import Arweave from "arweave";
import { useGateway } from "~gateways/wayfinder";
import aoLogo from "url:/assets/ecosystem/ao-logo.svg";
import { getUserAvatar } from "~lib/avatar";
import { formatBalance } from "~utils/format";
Expand All @@ -34,6 +28,7 @@ import BigNumber from "bignumber.js";
import JSConfetti from "js-confetti";
import browser from "webextension-polyfill";
import { AO_NATIVE_TOKEN } from "~utils/ao_import";
import { useBalance } from "~wallets/hooks";

export default function Token({ onClick, ...props }: Props) {
const ref = useRef(null);
Expand Down Expand Up @@ -166,13 +161,13 @@ export default function Token({ onClick, ...props }: Props) {
{props?.loading ? (
<Skeleton width="80px" height="20px" />
) : props?.error ? (
<TooltipV2 content={DegradedMessage} position="left">
<MessageTooltip content={DegradedMessage} position="left">
<WarningIcon />
</TooltipV2>
</MessageTooltip>
) : props?.networkError ? (
<TooltipV2 content={NetworkErrorMessage} position="left">
<MessageTooltip content={NetworkErrorMessage} position="left">
<NetworkErrorIcon />
</TooltipV2>
</MessageTooltip>
) : (
<>
{showTooltip ? (
Expand Down Expand Up @@ -373,6 +368,10 @@ const BalanceTooltip = styled(TooltipV2)`
margin-right: 1rem;
`;

const MessageTooltip = styled(TooltipV2)`
max-width: 290px;
`;

const Image = styled.img`
width: 16px;
padding: 0 8px;
Expand Down Expand Up @@ -486,33 +485,23 @@ export function ArToken({ onClick }: ArTokenProps) {
});

// load ar balance
const [balance, setBalance] = useState(BigNumber("0"));
const [fiatBalance, setFiatBalance] = useState(BigNumber("0"));
const [displayBalance, setDisplayBalance] = useState("0");
const [totalBalance, setTotalBalance] = useState("");
const [showTooltip, setShowTooltip] = useState(false);

// memoized requirements to ensure stability
const requirements = useMemo(() => ({ ensureStake: true }), []);
const gateway = useGateway(requirements);
const balance = useBalance();

useEffect(() => {
(async () => {
if (!activeAddress) return;

const arweave = new Arweave(gateway);

// fetch balance
const winstonBalance = await arweave.wallets.getBalance(activeAddress);
const arBalance = BigNumber(arweave.ar.winstonToAr(winstonBalance));
setBalance(arBalance);

const formattedBalance = formatBalance(arBalance);
const formattedBalance = formatBalance(balance);
setTotalBalance(formattedBalance.tooltipBalance);
setShowTooltip(formattedBalance.showTooltip);
setDisplayBalance(formattedBalance.displayBalance);
})();
}, [activeAddress, gateway]);
}, [activeAddress, balance]);

useEffect(() => {
setFiatBalance(balance.multipliedBy(price));
Expand Down
38 changes: 23 additions & 15 deletions src/components/popup/home/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Loading, TooltipV2 } from "@arconnect/components";
import { useEffect, useMemo, useState, type HTMLProps } from "react";
import { useStorage } from "@plasmohq/storage/hook";
import { ExtensionStorage } from "~utils/storage";
import { useHistory } from "~utils/hash_router";
import { useBalance } from "~wallets/hooks";
import { getArPrice } from "~lib/coingecko";
import { getAppURL } from "~utils/format";
Expand All @@ -25,8 +24,8 @@ import styled from "styled-components";
import Arweave from "arweave";
import { removeDecryptionKey } from "~wallets/auth";
import { findGateway } from "~gateways/wayfinder";
import type { Gateway } from "~gateways/gateway";
import BigNumber from "bignumber.js";
import { retryWithDelay, retryWithDelayAndTimeout } from "~utils/retry";

export default function Balance() {
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -103,8 +102,7 @@ export default function Balance() {
(async () => {
if (!activeAddress) return;
setLoading(true);
const gateway = await findGateway({ graphql: true });
const history = await balanceHistory(activeAddress, gateway);
const history = await balanceHistory(activeAddress);

setHistoricalBalance(history);
setLoading(false);
Expand Down Expand Up @@ -192,8 +190,9 @@ export default function Balance() {
);
}

async function balanceHistory(address: string, gateway: Gateway) {
const arweave = new Arweave(gateway);
async function balanceHistory(address: string) {
const gateway = await findGateway({ graphql: true });
let arweave = new Arweave(gateway);
let minHeight = 0;
try {
const { height } = await arweave.network.getInfo();
Expand All @@ -203,8 +202,9 @@ async function balanceHistory(address: string, gateway: Gateway) {

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

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

Expand All @@ -266,9 +269,14 @@ async function balanceHistory(address: string, gateway: Gateway) {
.sort((a, b) => b.block.timestamp - a.block.timestamp); // Sort by newest to oldest

// Get the current balance
let balance = BigNumber(
arweave.ar.winstonToAr(await arweave.wallets.getBalance(address))
);
const winstonBalance = await retryWithDelayAndTimeout(async () => {
const gateway = await findGateway({});
arweave = new Arweave(gateway);
const balance = await arweave.wallets.getBalance(address);
if (isNaN(+balance)) throw new Error("Balance is invalid");
return balance;
});
let balance = BigNumber(arweave.ar.winstonToAr(winstonBalance));

// Initialize the result array with the current balance
const res = [balance.toNumber()];
Expand Down
15 changes: 7 additions & 8 deletions src/components/popup/home/Transactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,13 @@ export default function Transactions() {
: "Pending"}
</Secondary>
</Section>
{transaction.transactionType !== "printArchive" && (
<Section alignRight>
<Main>{getFormattedAmount(transaction)}</Main>
<Secondary>
{getFormattedFiatAmount(transaction, arPrice, currency)}
</Secondary>
</Section>
)}

<Section alignRight>
<Main>{getFormattedAmount(transaction)}</Main>
<Secondary>
{getFormattedFiatAmount(transaction, arPrice, currency)}
</Secondary>
</Section>
</Transaction>
</TransactionItem>
))
Expand Down
15 changes: 14 additions & 1 deletion src/lib/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export const getFormattedAmount = (transaction: ExtendedTransaction) => {
}).toFixed()} ${transaction.aoInfo.tickerName}`;
}
return "";
case "printArchive":
return `${parseFloat(transaction.node.fee.ar).toFixed(3)} AR`;
default:
return "";
}
Expand All @@ -154,11 +156,22 @@ export const getFormattedFiatAmount = (
currency: string
) => {
try {
if (transaction.node.quantity) {
if (
transaction.node.quantity &&
transaction.transactionType !== "printArchive"
) {
const fiatBalance = BigNumber(transaction.node.quantity.ar).multipliedBy(
arPrice
);
return formatFiatBalance(fiatBalance, currency);
} else if (
transaction.node.fee &&
transaction.transactionType === "printArchive"
) {
const fiatBalance = BigNumber(transaction.node.fee.ar).multipliedBy(
arPrice
);
return formatFiatBalance(fiatBalance, currency);
}
} catch {}
return "";
Expand Down
3 changes: 3 additions & 0 deletions src/notifications/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export type RawTransaction = {
quantity: {
ar: string;
};
fee: {
ar: string;
};
block: {
timestamp: number;
height: number;
Expand Down
1 change: 1 addition & 0 deletions src/notifications/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ query ($address: String!) {
recipient
owner { address }
quantity { ar }
fee { ar }
block { timestamp, height }
tags {
name
Expand Down
6 changes: 6 additions & 0 deletions src/routes/popup/transaction/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,12 @@ export default function Transaction({ id: rawId, gw, message }: Props) {
</div>
</PropertyValue>
</TransactionProperty>
<TransactionProperty>
<PropertyName>
{browser.i18n.getMessage("transaction_fee")}
</PropertyName>
<PropertyValue>{transaction.fee.ar} AR</PropertyValue>
</TransactionProperty>
{!message && (
<TransactionProperty>
<PropertyName>
Expand Down
39 changes: 1 addition & 38 deletions src/tokens/aoTokens/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Id,
Owner
} from "./ao";
import { withRetry } from "~utils/retry";

/** Tokens storage name */
const AO_TOKENS = "ao_tokens";
Expand All @@ -36,44 +37,6 @@ const gateway = {
protocol: "https"
};

/**
* Generic retry function for any async operation.
* @param fn - The async function to be retried.
* @param maxRetries - Maximum retry attempts.
* @param retryDelay - Delay between retries in milliseconds.
* @returns A promise of the type that the async function returns.
*/
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
retryDelay: number = 100
): Promise<T> {
let lastError: any;

const delay = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));

for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (attempt < maxRetries) {
const waitTime = Math.pow(2, attempt - 1) * retryDelay;
console.log(`Attempt ${attempt} failed, retrying in ${waitTime}ms...`);
await delay(waitTime);
} else {
console.error(
`All ${maxRetries} attempts failed. Last error:`,
lastError
);
}
}
}

throw lastError;
}

async function getTokenInfo(id: string): Promise<TokenInfo> {
const body = {
Id,
Expand Down
Loading
Loading