Skip to content

Commit

Permalink
Merge branch 'dev' into fix/slot-blocks-cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
brancoder authored Apr 25, 2024
2 parents 780814b + 3addd46 commit b34d604
Show file tree
Hide file tree
Showing 16 changed files with 116 additions and 49 deletions.
4 changes: 2 additions & 2 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "explorer-api",
"description": "API for Tangle Explorer",
"version": "3.3.8-rc.2",
"version": "3.3.8",
"author": "Martyn Janes <[email protected]>",
"repository": {
"type": "git",
Expand Down
8 changes: 6 additions & 2 deletions api/src/utils/stardust/associatedOutputsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,19 @@ export class AssociatedOutputsHelper {
// remove expired basic outputs from basic address associations if they exist
const expiredIds = this.associationToOutputIds.get(AssociationType.BASIC_ADDRESS_EXPIRED);
const filteredOutputIds = outputIds.filter((id) => !expiredIds?.includes(id));
associations.push({ type, outputIds: filteredOutputIds.reverse() });
if (filteredOutputIds.length > 0) {
associations.push({ type, outputIds: filteredOutputIds.reverse() });
}
} else if (
type === AssociationType.NFT_ADDRESS &&
this.associationToOutputIds.get(AssociationType.NFT_ADDRESS_EXPIRED)?.length > 0
) {
// remove expired nft outputs from nft address associations if they exist
const expiredIds = this.associationToOutputIds.get(AssociationType.NFT_ADDRESS_EXPIRED);
const filteredOutputIds = outputIds.filter((id) => !expiredIds?.includes(id));
associations.push({ type, outputIds: filteredOutputIds.reverse() });
if (filteredOutputIds.length > 0) {
associations.push({ type, outputIds: filteredOutputIds.reverse() });
}
} else {
associations.push({ type, outputIds: outputIds.reverse() });
}
Expand Down
6 changes: 3 additions & 3 deletions api/src/utils/stardust/searchExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class SearchExecutor {
this.apiService
.milestoneDetailsById(searchQuery.milestoneId)
.then((milestoneDetails) => {
if (milestoneDetails) {
if (milestoneDetails.blockId) {
promisesResult = {
milestone: milestoneDetails,
};
Expand Down Expand Up @@ -139,7 +139,7 @@ export class SearchExecutor {
this.apiService
.aliasDetails(searchQuery.aliasId)
.then((aliasOutputs) => {
if (aliasOutputs) {
if (aliasOutputs.aliasDetails) {
promisesResult = {
aliasId: searchQuery.aliasId,
did: searchQuery.did,
Expand All @@ -162,7 +162,7 @@ export class SearchExecutor {
this.apiService
.nftDetails(searchQuery.nftId)
.then((nftOutputs) => {
if (nftOutputs) {
if (nftOutputs.nftDetails) {
promisesResult = {
nftId: searchQuery.nftId,
};
Expand Down
3 changes: 3 additions & 0 deletions client/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ RUN echo 'server {\
}\
}' > /etc/nginx/sites-available/default

# Set Content-Type so streaming compilation works
RUN mv ./nginx/wasm.conf /etc/nginx/conf.d/wasm.conf

# Running required steps to prepare the web app prod build
RUN npm install
RUN npm run build
Expand Down
4 changes: 4 additions & 0 deletions client/nginx/wasm.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
types {
# Set Content-Type so streaming compilation works
application/wasm wasm;
}
4 changes: 2 additions & 2 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "explorer-client",
"description": "Tangle Explorer UI",
"version": "3.3.8-rc.2",
"version": "3.3.8",
"author": "Martyn Janes <[email protected]>",
"type": "module",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/components/nova/ContextInputView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ContextInputView: React.FC<IContextInputViewProps> = ({ contextInput }) =>
<div className="section--data">
<div className="label">Account</div>
<div className="value code highlight">
<TruncatedId id={bech32Address} link={`/${network}/account/${bech32Address}`} showCopyButton />
<TruncatedId id={bech32Address} link={`/${network}/addr/${bech32Address}`} showCopyButton />
</div>
</div>
);
Expand Down
6 changes: 4 additions & 2 deletions client/src/app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import StardustBlock from "./routes/stardust/Block";
import StardustFoundry from "./routes/stardust/Foundry";
import { Landing as StardustLanding } from "./routes/stardust/landing/Landing";
import NovaLanding from "./routes/nova/landing/Landing";
import NftRedirectRoute from "./routes/stardust/NftRedirectRoute";
import NftRedirectRouteStardust from "./routes/stardust/NftRedirectRoute";
import NftRedirectRouteNova from "./routes/nova/NftRedirectRoute";
import StardustOutputList from "./routes/stardust/OutputList";
import StardustOutputPage from "./routes/stardust/OutputPage";
import NovaBlockPage from "./routes/nova/Block";
Expand Down Expand Up @@ -169,7 +170,7 @@ const buildAppRoutes = (protocolVersion: string, withNetworkContext: (wrappedCom
<Route path="/:network/visualizer/" key={keys.next().value} component={StardustVisualizer} />,
<Route path="/:network/search/:query?" key={keys.next().value} component={StardustSearch} />,
<Route path="/:network/addr/:address" key={keys.next().value} component={StardustAddressPage} />,
<Route path="/:network/nft/:nftId" key={keys.next().value} component={NftRedirectRoute} />,
<Route path="/:network/nft/:nftId" key={keys.next().value} component={NftRedirectRouteStardust} />,
<Route path="/:network/block/:blockId" key={keys.next().value} component={StardustBlock} />,
<Route path="/:network/transaction/:transactionId" key={keys.next().value} component={StardustTransactionPage} />,
<Route path="/:network/output/:outputId" key={keys.next().value} component={StardustOutputPage} />,
Expand All @@ -189,6 +190,7 @@ const buildAppRoutes = (protocolVersion: string, withNetworkContext: (wrappedCom
<Route path="/:network/epoch/:epochIndex" key={keys.next().value} component={NovaEpochPage} />,
<Route path="/:network/transaction/:transactionId" key={keys.next().value} component={NovaTransactionPage} />,
<Route path="/:network/foundry/:foundryId" key={keys.next().value} component={NovaFoundryPage} />,
<Route path="/:network/nft/:nftId" key={keys.next().value} component={NftRedirectRouteNova} />,
<Route path="/:network/statistics" key={keys.next().value} component={NovaStatisticsPage} />,
<Route path="/:network/validators" key={keys.next().value} component={ValidatorsPage} />,
<Route path="/:network/outputs" key={keys.next().value} component={NovaOutputsPage} />,
Expand Down
36 changes: 36 additions & 0 deletions client/src/app/routes/nova/NftRedirectRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { AddressType } from "@iota/sdk-wasm-nova/web";
import React from "react";
import { Redirect, RouteComponentProps } from "react-router-dom";
import { AddressHelper } from "~helpers/nova/addressHelper";
import { useNetworkInfoNova } from "~/helpers/nova/networkInfo";

interface NftRedirectRouteProps {
/**
* The network.
*/
network: string;

/**
* The nftId to redirect.
*/
nftId: string;
}

const ADDRESS_ROUTE = "addr";

const NftRedirectRoute: React.FC<RouteComponentProps<NftRedirectRouteProps>> = ({
match: {
params: { network, nftId },
},
}) => {
const { bech32Hrp } = useNetworkInfoNova((s) => s.networkInfo);
const nftAddress = AddressHelper.buildAddress(bech32Hrp, nftId, AddressType.Nft);
const redirectState = {
addressDetails: nftAddress,
};
const routeParam = nftAddress.bech32;
const redirect = `/${network}/${ADDRESS_ROUTE}/${routeParam}`;
return <Redirect to={{ pathname: redirect, state: redirectState }} />;
};

export default NftRedirectRoute;
34 changes: 26 additions & 8 deletions client/src/helpers/nova/preExpandedConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import {
AccountOutput,
AccountUnlock,
AddressType,
AddressUnlockCondition,
CommonOutput,
ExpirationUnlockCondition,
Expand All @@ -7,12 +10,11 @@ import {
StateControllerAddressUnlockCondition,
Unlock,
UnlockConditionType,
Utils,
UnlockType,
} from "@iota/sdk-wasm-nova/web";
import { AddressHelper } from "~/helpers/nova/addressHelper";
import { IInput } from "~models/api/nova/IInput";
import { IPreExpandedConfig } from "~models/components";
import { resolveTransitiveUnlock } from "./resolveTransiviteUnlock";

const OUTPUT_EXPAND_CONDITIONS: UnlockConditionType[] = [
UnlockConditionType.Address,
Expand All @@ -37,25 +39,28 @@ export function getInputsPreExpandedConfig(inputs: IInput[], unlocks: Unlock[],
const matchExpandCondition = commonOutput.unlockConditions?.find((unlockCondition) =>
INPUT_EXPAND_CONDITIONS.includes(unlockCondition.type),
);

preExpandedConfig = {
isPreExpanded: !!matchExpandCondition,
};
if (input?.output?.output && "unlockConditions" in input.output.output) {
const commmonOutput = input.output.output as unknown as CommonOutput;

const signatureUnlock = resolveTransitiveUnlock(unlocks, idx);
const unlockSignatureAddress = Utils.addressToBech32(Utils.publicKeyHash(signatureUnlock.signature.publicKey), bech32Hrp);
if (commonOutput.unlockConditions.length > 0) {
const unlockSignatureAddress = input.address.bech32;

preExpandedConfig = {
...preExpandedConfig,
unlockConditions: commmonOutput.unlockConditions?.map((unlockCondition) => {
unlockConditions: commonOutput.unlockConditions.map((unlockCondition) => {
switch (unlockCondition.type) {
case UnlockConditionType.Address: {
const unlockAddress = AddressHelper.buildAddress(
bech32Hrp,
(unlockCondition as AddressUnlockCondition).address,
)?.bech32;
return unlockAddress === unlockSignatureAddress;

// special case for account unlock
const referencedAccountAddress = getReferencedAddress(inputs, unlocks[idx], bech32Hrp);

return unlockAddress === unlockSignatureAddress || unlockAddress === referencedAccountAddress;
}
case UnlockConditionType.Expiration: {
const unlockAddress = AddressHelper.buildAddress(
Expand Down Expand Up @@ -90,6 +95,19 @@ export function getInputsPreExpandedConfig(inputs: IInput[], unlocks: Unlock[],
return inputsPreExpandedConfig;
}

function getReferencedAddress(inputs: IInput[], unlock: Unlock, bech32Hrp: string): string {
let referencedAccountAddress = "";
if (unlock.type === UnlockType.Account) {
const referencedAccountInput = inputs[(unlock as AccountUnlock).reference];
const referencedAccountOutput = referencedAccountInput?.output?.output as unknown as AccountOutput;
if (referencedAccountOutput?.accountId) {
referencedAccountAddress =
AddressHelper.buildAddress(bech32Hrp, referencedAccountOutput.accountId, AddressType.Account)?.bech32 || "";
}
}
return referencedAccountAddress;
}

/**
* Get the preExpandedConfig for the outputs.
* Expand the output and its relevant receiver address related unlock conditions.
Expand Down
5 changes: 2 additions & 3 deletions client/src/helpers/nova/transactionsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,7 @@ export class TransactionsHelper {
}

sortedOutputs = [...outputs, ...remainderOutputs];
this.sortInputsAndOuputsByIndex(sortedOutputs);
this.sortInputsAndOuputsByIndex(inputs);
this.sortOuputsByIndex(sortedOutputs);
}

return { inputs, outputs: sortedOutputs, unlockAddresses, transferTotal };
Expand All @@ -191,7 +190,7 @@ export class TransactionsHelper {
* Sort inputs and outputs in assending order by index.
* @param items Inputs or Outputs.
*/
public static sortInputsAndOuputsByIndex(items: IInput[] | IOutput[]) {
public static sortOuputsByIndex(items: IOutput[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items.sort((a: any, b: any) => {
const firstIndex: string = a.id ? a.id.slice(-4) : a.outputId.slice(-4);
Expand Down
42 changes: 22 additions & 20 deletions client/src/helpers/stardust/hooks/useAddressBalance.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { AddressType, AliasOutput, NftOutput } from "@iota/sdk-wasm-stardust/web";
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import NetworkContext from "~/app/context/NetworkContext";
import { IBech32AddressDetails } from "~/models/api/IBech32AddressDetails";
import { ServiceFactory } from "~factories/serviceFactory";
import { useIsMounted } from "~helpers/hooks/useIsMounted";
import { STARDUST } from "~models/config/protocolVersion";
import { StardustApiClient } from "~services/stardust/stardustApiClient";
import { TransactionsHelper } from "../transactionsHelper";

/**
* Fetch the address balance
Expand All @@ -23,6 +25,7 @@ export function useAddressBalance(
const [balance, setBalance] = useState<number | null>(null);
const [availableBalance, setAvailableBalance] = useState<number | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const { rentStructure } = useContext(NetworkContext);

useEffect(() => {
setIsLoading(true);
Expand All @@ -33,28 +36,27 @@ export function useAddressBalance(
// eslint-disable-next-line no-void
void (async () => {
const response = await apiClient.addressBalanceChronicle({ network, address });

if (response?.totalBalance !== undefined && isMounted) {
let totalBalance = response.totalBalance;
let availableBalance = response.availableBalance ?? 0;
if (isMounted) {
let totalBalance = 0;
let availableBalance = null;
if (response?.totalBalance !== undefined) {
totalBalance = response.totalBalance;
availableBalance = response.availableBalance ?? 0;
} else {
// Fallback balance from iotajs (node)
const addressDetailsWithBalance = await apiClient.addressBalance({ network, address });
if (addressDetailsWithBalance && isMounted) {
totalBalance = Number(addressDetailsWithBalance.balance);
}
}
if (output) {
totalBalance = Number(totalBalance) + Number(output.amount);
availableBalance = Number(availableBalance) + Number(output.amount);
const outputBalance = Number(output.amount);
const outputStorageDeposit = TransactionsHelper.computeStorageDeposit([output], rentStructure);
totalBalance = Number(totalBalance ?? 0) + outputBalance;
availableBalance = Number(availableBalance ?? 0) + outputBalance - outputStorageDeposit;
}
setBalance(totalBalance);
setAvailableBalance(availableBalance > 0 ? availableBalance : null);
} else if (isMounted) {
// Fallback balance from iotajs (node)
const addressDetailsWithBalance = await apiClient.addressBalance({ network, address });

if (addressDetailsWithBalance && isMounted) {
let totalBalance = Number(addressDetailsWithBalance.balance);
if (output) {
totalBalance = Number(totalBalance) + Number(output.amount);
}
setBalance(totalBalance);
setAvailableBalance(null);
}
setAvailableBalance(availableBalance);
}
})();
} else {
Expand Down
5 changes: 2 additions & 3 deletions client/src/helpers/stardust/transactionsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ export class TransactionsHelper {
}

sortedOutputs = [...outputs, ...remainderOutputs];
this.sortInputsAndOuputsByIndex(sortedOutputs);
this.sortInputsAndOuputsByIndex(inputs);
this.sortOuputsByIndex(sortedOutputs);
}

return { inputs, unlocks, outputs: sortedOutputs, unlockAddresses, transferTotal };
Expand All @@ -189,7 +188,7 @@ export class TransactionsHelper {
* Sort inputs and outputs in assending order by index.
* @param items Inputs or Outputs.
*/
public static sortInputsAndOuputsByIndex(items: IInput[] | IOutput[]) {
public static sortOuputsByIndex(items: IOutput[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items.sort((a: any, b: any) => {
const firstIndex: string = a.id ? a.id.slice(-4) : a.outputId.slice(-4);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "explorer",
"description": "Tangle Explorer",
"version": "3.3.8-rc.2",
"version": "3.3.8",
"scripts": {
"setup:client": "cd client && npm install && npm run postinstall",
"setup:api": "cd api && npm install && npm run build-compile && npm run build-config",
Expand Down

0 comments on commit b34d604

Please sign in to comment.