Skip to content

Commit

Permalink
Fix: Improve Address conversions (#1194)
Browse files Browse the repository at this point in the history
* chore: Bump sdk-nova version to latest commit

* chore: Improve nova address helper

* feat: Remove dependency on specific address to bech32 Utils methods

* fix: nft address calculation and typo in function naming

* fix: variable name

---------

Co-authored-by: Branko Bosnic <[email protected]>
  • Loading branch information
msarcev and brancoder authored Feb 28, 2024
1 parent e895097 commit f124557
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nova-build-temp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
TARGET_COMMIT:
description: "Target Commit Hash for the SDK"
required: false
default: "aa1b1de58731dbbf9dd0f5e2960fd11b0056b633"
default: "772a5665afb7663b5ddb2c1e4780d03401fc7aa2"
environment:
type: choice
description: "Select the environment to deploy to"
Expand Down
1 change: 0 additions & 1 deletion api/src/models/api/nova/IAddressDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ export interface IAddressDetails {
hex?: string;
type?: AddressType;
label?: string;
capabilities?: number[];
}
34 changes: 22 additions & 12 deletions api/src/utils/nova/addressHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ImplicitAccountCreationAddress,
} from "@iota/sdk-nova";
import { plainToInstance } from "class-transformer";
import logger from "../../logger";
import { IAddressDetails } from "../../models/api/nova/IAddressDetails";
import { HexHelper } from "../hexHelper";

Expand All @@ -31,6 +32,7 @@ export class AddressHelper {
let bech32: string;
let hex: string;
let type: AddressType;

if (Utils.isAddressValid(addressString)) {
try {
const address: Address = Utils.parseBech32Address(addressString);
Expand All @@ -41,27 +43,28 @@ export class AddressHelper {
hex = Utils.bech32ToHex(addressString);
}
} catch (e) {
console.error(e);
logger.debug(`Failed parsing Address. Cause: ${e}`);
}
}

if (!bech32) {
// We assume this is hex
hex = addressString;

if (typeHint) {
bech32 = this.computeBech32FromHexAndType(hex, type, hrp);
bech32 = this.computeBech32FromHexAndType(hex, typeHint, hrp);
}
}

return {
bech32,
hex: hex ? HexHelper.addPrefix(hex) : hex,
type,
type: type ?? typeHint,
label: AddressHelper.typeLabel(type),
};
}

private static buildAddressFromTypes(address: Address, hrp: string, capabilities?: number[]): IAddressDetails {
private static buildAddressFromTypes(address: Address, hrp: string): IAddressDetails {
let hex: string = "";
let bech32: string = "";

Expand All @@ -79,31 +82,34 @@ export class AddressHelper {
hex = innerAddress.pubKeyHash;
}

bech32 = this.computeBech32FromHexAndType(hex, address.type, hrp);
bech32 = Utils.addressToBech32(address, hrp);

return {
bech32,
hex,
type: address.type,
label: AddressHelper.typeLabel(address.type),
capabilities,
};
}

private static computeBech32FromHexAndType(hex: string, addressType: AddressType, hrp: string) {
let bech32 = "";
let address: Address | null = null;

if (addressType === AddressType.Ed25519) {
bech32 = Utils.hexToBech32(hex, hrp);
address = new Ed25519Address(hex);
} else if (addressType === AddressType.Account) {
bech32 = Utils.accountIdToBech32(hex, hrp);
address = new AccountAddress(hex);
} else if (addressType === AddressType.Nft) {
bech32 = Utils.nftIdToBech32(hex, hrp);
address = new NftAddress(hex);
} else if (addressType === AddressType.Anchor) {
// Update to Utils.anchorIdToBech32 when it gets implemented
bech32 = Utils.accountIdToBech32(hex, hrp);
address = new AnchorAddress(hex);
} else if (addressType === AddressType.ImplicitAccountCreation) {
bech32 = Utils.hexToBech32(hex, hrp);
address = new ImplicitAccountCreationAddress(hex);
}

if (address !== null) {
bech32 = Utils.addressToBech32(address, hrp);
}

return bech32;
Expand All @@ -123,6 +129,10 @@ export class AddressHelper {
return "NFT";
} else if (addressType === AddressType.Anchor) {
return "Anchor";
} else if (addressType === AddressType.ImplicitAccountCreation) {
return "Implicit Account Creation";
}

return "Unknown";
}
}
20 changes: 12 additions & 8 deletions client/src/app/components/nova/OutputView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
SimpleTokenScheme,
DelegationOutput,
Utils,
AccountAddress,
NftAddress,
} from "@iota/sdk-wasm-nova/web";
import UnlockConditionView from "./UnlockConditionView";
import CopyButton from "../CopyButton";
Expand Down Expand Up @@ -40,7 +42,7 @@ const OutputView: React.FC<OutputViewProps> = ({ outputId, output, showCopyAmoun
const [isFormattedBalance, setIsFormattedBalance] = useState(true);
const { bech32Hrp, name: network } = useNetworkInfoNova((s) => s.networkInfo);

const aliasOrNftBech32 = buildAddressForAliasOrNft(outputId, output, bech32Hrp);
const accountOrNftBech32 = buildAddressForAccountOrNft(outputId, output, bech32Hrp);
const outputIdTransactionPart = `${outputId.slice(0, 8)}....${outputId.slice(-8, -4)}`;
const outputIdIndexPart = outputId.slice(-4);
const manaEntries = getManaKeyValueEntries(manaDetails);
Expand Down Expand Up @@ -99,8 +101,8 @@ const OutputView: React.FC<OutputViewProps> = ({ outputId, output, showCopyAmoun
<div className="card--label">Account address:</div>
<div className="card--value">
<TruncatedId
id={aliasOrNftBech32}
link={isLinksDisabled ? undefined : `/${network}/addr/${aliasOrNftBech32}`}
id={accountOrNftBech32}
link={isLinksDisabled ? undefined : `/${network}/addr/${accountOrNftBech32}`}
showCopyButton
/>
</div>
Expand All @@ -127,8 +129,8 @@ const OutputView: React.FC<OutputViewProps> = ({ outputId, output, showCopyAmoun
<div className="card--label">Nft address:</div>
<div className="card--value">
<TruncatedId
id={aliasOrNftBech32}
link={isLinksDisabled ? undefined : `/${network}/addr/${aliasOrNftBech32}`}
id={accountOrNftBech32}
link={isLinksDisabled ? undefined : `/${network}/addr/${accountOrNftBech32}`}
showCopyButton
/>
</div>
Expand Down Expand Up @@ -215,19 +217,21 @@ const OutputView: React.FC<OutputViewProps> = ({ outputId, output, showCopyAmoun
);
};

function buildAddressForAliasOrNft(outputId: string, output: Output, bech32Hrp: string): string {
function buildAddressForAccountOrNft(outputId: string, output: Output, bech32Hrp: string): string {
let bech32: string = "";

if (output.type === OutputType.Account) {
const accountIdFromOutput = (output as AccountOutput).accountId;
const accountId = HexHelper.toBigInt256(accountIdFromOutput).eq(bigInt.zero)
? Utils.computeAccountId(outputId)
: accountIdFromOutput;
bech32 = Utils.accountIdToBech32(accountId, bech32Hrp);
const accountAddress = new AccountAddress(accountId);
bech32 = Utils.addressToBech32(accountAddress, bech32Hrp);
} else if (output.type === OutputType.Nft) {
const nftIdFromOutput = (output as NftOutput).nftId;
const nftId = HexHelper.toBigInt256(nftIdFromOutput).eq(bigInt.zero) ? Utils.computeNftId(outputId) : nftIdFromOutput;
bech32 = Utils.nftIdToBech32(nftId, bech32Hrp);
const nftAddress = new NftAddress(nftId);
bech32 = Utils.addressToBech32(nftAddress, bech32Hrp);
}

return bech32;
Expand Down
9 changes: 5 additions & 4 deletions client/src/app/components/nova/address/section/nft/Nft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { tryParseMetadata } from "~helpers/stardust/metadataUtils";
import { INftImmutableMetadata } from "~models/api/stardust/nft/INftImmutableMetadata";
import "./Nft.scss";
import { useNetworkInfoNova } from "~/helpers/nova/networkInfo";
import { MetadataFeature, NftOutput, Utils } from "@iota/sdk-wasm-nova/web";
import { MetadataFeature, NftAddress, NftOutput, Utils } from "@iota/sdk-wasm-nova/web";
import TruncatedId from "~/app/components/stardust/TruncatedId";
import { TransactionsHelper } from "~/helpers/nova/transactionsHelper";

Expand All @@ -32,7 +32,8 @@ const Nft: React.FC<NftProps> = ({ nftOutput }) => {
const [metadata, setMetadata] = useState<MetadataFeature | null>(null);
const [issuerId, setIssuerId] = useState<string | null>(null);
const [standardMetadata, setStandardMetadata] = useState<INftImmutableMetadata | null>();
const nftAddress = Utils.hexToBech32(nftOutput.nftId, bech32Hrp);
const nftAddress = new NftAddress(nftOutput.nftId);
const nftBech32Address = Utils.addressToBech32(nftAddress, bech32Hrp);
const [isWhitelisted] = useTokenRegistryNftCheck(issuerId, nftOutput.nftId);
const [name, setName] = useState<string | null>();
const [uri, isNftUriLoading] = useNftMetadataUri(standardMetadata?.uri);
Expand Down Expand Up @@ -75,9 +76,9 @@ const Nft: React.FC<NftProps> = ({ nftOutput }) => {
return (
<div className="nft-card">
<div className="nft-card__metadata">
<Link to={`/${network}/addr/${nftAddress}`}>{nftImageContent}</Link>
<Link to={`/${network}/addr/${nftBech32Address}`}>{nftImageContent}</Link>
<span className="nft-card__id">
<TruncatedId id={nftOutput.nftId} link={`/${network}/addr/${nftAddress}`} />
<TruncatedId id={nftOutput.nftId} link={`/${network}/addr/${nftBech32Address}`} />
</span>
</div>
{name && isWhitelisted && <span className="nft-card__name truncate">{name}</span>}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { TRANSACTION_FAILURE_REASON_STRINGS, Transaction, TransactionMetadata, TransactionState, Utils } from "@iota/sdk-wasm-nova/web";
import {
TRANSACTION_FAILURE_REASON_STRINGS,
Transaction,
TransactionMetadata,
TransactionState,
Utils,
AccountAddress,
} from "@iota/sdk-wasm-nova/web";
import React from "react";
import Spinner from "../../../Spinner";
import TruncatedId from "~/app/components/stardust/TruncatedId";
Expand Down Expand Up @@ -63,15 +70,20 @@ const TransactionMetadataSection: React.FC<TransactionMetadataSectionProps> = ({
{transaction?.allotments && (
<div className="section--data">
<div className="label">Mana Allotment Accounts</div>
{transaction?.allotments?.map((allotment, idx) => (
<div className="value code highlight margin-b-t" key={idx}>
<TruncatedId
id={allotment.accountId}
link={`/${network}/addr/${Utils.accountIdToBech32(allotment.accountId, bech32Hrp)}`}
showCopyButton
/>
</div>
))}
{transaction?.allotments?.map((allotment, idx) => {
const accountAddress = new AccountAddress(allotment.accountId);
const accountBech32 = Utils.addressToBech32(accountAddress, bech32Hrp);

return (
<div className="value code highlight margin-b-t" key={idx}>
<TruncatedId
id={allotment.accountId}
link={`/${network}/addr/${accountBech32}`}
showCopyButton
/>
</div>
);
})}
</div>
)}
</>
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/routes/nova/TransactionPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/jsx-no-useless-fragment */
import { BasicBlockBody, SignedTransactionPayload, Utils } from "@iota/sdk-wasm-nova/web";
import { AccountAddress, BasicBlockBody, SignedTransactionPayload, Utils } from "@iota/sdk-wasm-nova/web";
import React, { useEffect, useState } from "react";
import { RouteComponentProps } from "react-router-dom";
import metadataInfoMessage from "~assets/modals/stardust/block/metadata.json";
Expand Down Expand Up @@ -135,7 +135,7 @@ const TransactionPage: React.FC<RouteComponentProps<TransactionPageProps>> = ({
<div className="value code highlight">
<TruncatedId
id={block.header.issuerId}
link={`/${network}/addr/${Utils.accountIdToBech32(block.header.issuerId, bech32Hrp)}`}
link={`/${network}/addr/${Utils.addressToBech32(new AccountAddress(block.header.issuerId), bech32Hrp)}`}
showCopyButton={true}
/>
</div>
Expand Down
31 changes: 18 additions & 13 deletions client/src/helpers/nova/addressHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class AddressHelper {
}

if (!bech32) {
// We assume this is hex and either use the hint or assume ed25519
// We assume this is hex
hex = addressString;
type = typeHint ?? AddressType.Ed25519;
bech32 = this.computeBech32FromHexAndType(hex, type, hrp);
Expand All @@ -51,12 +51,12 @@ export class AddressHelper {
return {
bech32,
hex: hex ? HexHelper.addPrefix(hex) : hex,
type,
type: type ?? typeHint,
label: AddressHelper.typeLabel(type),
};
}

private static buildAddressFromTypes(address: Address, hrp: string, capabilities?: number[]): IAddressDetails {
private static buildAddressFromTypes(address: Address, hrp: string): IAddressDetails {
let hex: string = "";
let bech32: string = "";

Expand All @@ -74,31 +74,34 @@ export class AddressHelper {
hex = (innerAddress as Ed25519Address).pubKeyHash;
}

bech32 = this.computeBech32FromHexAndType(hex, address.type, hrp);
bech32 = Utils.addressToBech32(address, hrp);

return {
bech32,
hex,
type: address.type,
label: AddressHelper.typeLabel(address.type),
capabilities,
};
}

private static computeBech32FromHexAndType(hex: string, addressType: AddressType, hrp: string) {
let bech32 = "";
let address: Address | null = null;

if (addressType === AddressType.Ed25519) {
bech32 = Utils.hexToBech32(hex, hrp);
address = new Ed25519Address(hex);
} else if (addressType === AddressType.Account) {
bech32 = Utils.accountIdToBech32(hex, hrp);
address = new AccountAddress(hex);
} else if (addressType === AddressType.Nft) {
bech32 = Utils.nftIdToBech32(hex, hrp);
address = new NftAddress(hex);
} else if (addressType === AddressType.Anchor) {
// TODO Utils.anchorIdToBech32 does not exist https://github.com/iotaledger/iota-sdk/issues/1973
bech32 = Utils.accountIdToBech32(hex, hrp);
address = new AnchorAddress(hex);
} else if (addressType === AddressType.ImplicitAccountCreation) {
bech32 = Utils.hexToBech32(hex, hrp);
address = new ImplicitAccountCreationAddress(hex);
}

if (address !== null) {
bech32 = Utils.addressToBech32(address, hrp);
}

return bech32;
Expand All @@ -109,7 +112,7 @@ export class AddressHelper {
* @param addressType The address type to get the label for.
* @returns The label.
*/
private static typeLabel(addressType?: number): string | undefined {
private static typeLabel(addressType?: AddressType): string | undefined {
if (addressType === AddressType.Ed25519) {
return "Ed25519";
} else if (addressType === AddressType.Account) {
Expand All @@ -119,7 +122,9 @@ export class AddressHelper {
} else if (addressType === AddressType.Anchor) {
return "Anchor";
} else if (addressType === AddressType.ImplicitAccountCreation) {
return "Implicit";
return "Implicit Account Creation";
}

return "Unknown";
}
}
1 change: 0 additions & 1 deletion client/src/models/api/nova/IAddressDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ export interface IAddressDetails {
hex?: string;
type?: AddressType;
label?: string;
capabilities?: number[];
}
2 changes: 1 addition & 1 deletion setup_nova.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
SDK_DIR="iota-sdk"
TARGET_COMMIT="aa1b1de58731dbbf9dd0f5e2960fd11b0056b633"
TARGET_COMMIT="772a5665afb7663b5ddb2c1e4780d03401fc7aa2"

if [ ! -d "$SDK_DIR" ]; then
git clone -b 2.0 [email protected]:iotaledger/iota-sdk.git
Expand Down

0 comments on commit f124557

Please sign in to comment.