Skip to content

Commit b354517

Browse files
authored
Merge pull request #91 from iotaledger/feat/resolve-address-bech32
Feat: Resolve nft/alias id to bech32 address
2 parents 5808e4b + a98e25c commit b354517

22 files changed

+326
-191
lines changed

src/app/components/tangle/Address.tsx

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/app/components/tangle/AddressProps.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/app/components/tangle/Bech32Address.tsx

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,103 @@
1+
import { ALIAS_ADDRESS_TYPE, ED25519_ADDRESS_TYPE } from "@iota/iota.js";
12
import React, { Component, ReactNode } from "react";
23
import { Link } from "react-router-dom";
4+
import { ServiceFactory } from "../../../factories/serviceFactory";
5+
import { NodeConfigService } from "../../../services/nodeConfigService";
6+
import { Bech32AddressHelper } from "../../../utils/bech32AddressHelper";
37
import { ClipboardHelper } from "../../../utils/clipboardHelper";
8+
import { NameHelper } from "../../../utils/nameHelper";
49
import MessageButton from "../layout/MessageButton";
510
import { Bech32AddressProps } from "./Bech32AddressProps";
11+
import { Bech32AddressState } from "./Bech32AddressState";
612

713
/**
814
* Component which will display an Bech32Address.
915
*/
10-
class Bech32Address extends Component<Bech32AddressProps> {
16+
class Bech32Address extends Component<Bech32AddressProps, Bech32AddressState> {
17+
/**
18+
* Create a new instance of Bech 32 Address
19+
* @param props The props.
20+
*/
21+
constructor(props: Bech32AddressProps) {
22+
super(props);
23+
24+
if (this.props.address) {
25+
const nodeConfigService = ServiceFactory.get<NodeConfigService>("node-config");
26+
27+
const hash = this.props.address.type === ED25519_ADDRESS_TYPE
28+
? this.props.address?.pubKeyHash
29+
: (this.props.address.type === ALIAS_ADDRESS_TYPE
30+
? this.props.address?.aliasId
31+
: this.props.address?.nftId);
32+
33+
this.state = {
34+
addressDetails: Bech32AddressHelper.buildAddress(
35+
hash,
36+
nodeConfigService.getBech32Hrp(),
37+
this.props.address.type
38+
)
39+
};
40+
} else if (this.props.addressDetails) {
41+
this.state = {
42+
addressDetails: this.props.addressDetails
43+
};
44+
}
45+
}
46+
1147
/**
1248
* Render the component.
1349
* @returns The node to render.
1450
*/
1551
public render(): ReactNode {
1652
return (
1753
<div className="bech32-address">
18-
{this.props.addressDetails?.bech32 && (
54+
{this.state.addressDetails.bech32 && (
1955
<React.Fragment>
2056
<div className="card--label">
21-
Address
57+
{this.state.addressDetails.type
58+
? NameHelper.getAddressTypeName(this.state.addressDetails.type)
59+
: "Address"}
2260
</div>
2361
<div className="card--value card--value__mono row">
2462
{this.props.activeLinks && (
2563
<Link
2664
className="margin-r-t"
27-
to={`/explorer/address/${this.props.addressDetails?.bech32}`}
65+
to={`/explorer/address/${this.state.addressDetails?.bech32}`}
2866
>
29-
{this.props.addressDetails.bech32}
67+
{this.state.addressDetails.bech32}
3068
</Link>
3169
)}
3270
{!this.props.activeLinks && (
33-
<span className="margin-r-t">{this.props.addressDetails.bech32}</span>
71+
<span className="margin-r-t">{this.state.addressDetails.bech32}</span>
3472
)}
3573
<MessageButton
36-
onClick={() => ClipboardHelper.copy(this.props.addressDetails?.bech32)}
74+
onClick={() => ClipboardHelper.copy(this.state.addressDetails?.bech32)}
3775
buttonType="copy"
3876
labelPosition="top"
3977
/>
4078
</div>
4179
</React.Fragment>
4280
)}
43-
{this.props.addressDetails?.typeLabel && this.props.addressDetails?.hex && (
81+
{this.props.showHexAddress &&
82+
this.state.addressDetails?.hex && (
4483
<React.Fragment>
4584
<div className="card--label">
46-
{this.props.addressDetails.typeLabel} Address
85+
{this.state.addressDetails.typeLabel} Address
4786
</div>
4887
<div className="card--value card--value__mono row">
4988
{this.props.activeLinks && (
5089
<Link
5190
className="margin-r-t"
52-
to={`/explorer/address/${this.props.addressDetails?.hex}`}
91+
to={`/explorer/address/${this.state.addressDetails?.hex}`}
5392
>
54-
{this.props.addressDetails?.hex}
93+
{this.state.addressDetails?.hex}
5594
</Link>
5695
)}
5796
{!this.props.activeLinks && (
58-
<span className="margin-r-t">{this.props.addressDetails?.hex}</span>
97+
<span className="margin-r-t">{this.state.addressDetails?.hex}</span>
5998
)}
6099
<MessageButton
61-
onClick={() => ClipboardHelper.copy(this.props.addressDetails?.hex)}
100+
onClick={() => ClipboardHelper.copy(this.state.addressDetails?.hex)}
62101
buttonType="copy"
63102
labelPosition="top"
64103
/>

src/app/components/tangle/Bech32AddressProps.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AddressTypes } from "@iota/iota.js";
12
import { IBech32AddressDetails } from "../../../models/IBech32AddressDetails";
23

34
export interface Bech32AddressProps {
@@ -7,7 +8,17 @@ export interface Bech32AddressProps {
78
activeLinks: boolean;
89

910
/**
10-
* The address details.
11+
* Show Hexadecimal address representation.
12+
*/
13+
showHexAddress: boolean;
14+
15+
/**
16+
* The address.
17+
*/
18+
address?: AddressTypes;
19+
20+
/**
21+
* The address.
1122
*/
1223
addressDetails?: IBech32AddressDetails;
1324
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { IBech32AddressDetails } from "../../../models/IBech32AddressDetails";
2+
3+
export interface Bech32AddressState {
4+
/**
5+
* The address details.
6+
*/
7+
addressDetails: IBech32AddressDetails;
8+
}

src/app/components/tangle/FeatureBlock.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import classNames from "classnames";
33
import React, { Component, ReactNode } from "react";
44
import { NameHelper } from "../../../utils/nameHelper";
55
import { ReactComponent as DropdownIcon } from "./../../../assets/dropdown-arrow.svg";
6-
import Address from "./Address";
6+
import Bech32Address from "./Bech32Address";
77
import { FeatureBlockProps } from "./FeatureBlockProps";
88
import { FeatureBlockState } from "./FeatureBlockState";
99

@@ -52,7 +52,9 @@ class FeatureBlock extends Component<FeatureBlockProps, FeatureBlockState> {
5252
<div className="card--content--border-l">
5353
{(this.props.featureBlock.type === SENDER_FEATURE_BLOCK_TYPE ||
5454
this.props.featureBlock.type === ISSUER_FEATURE_BLOCK_TYPE) && (
55-
<Address
55+
<Bech32Address
56+
activeLinks={false}
57+
showHexAddress={false}
5658
address={this.props.featureBlock.address}
5759
/>
5860
)}

src/app/components/tangle/MigratedFund.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import classNames from "classnames";
33
import React, { Component, ReactNode } from "react";
44
import { ServiceFactory } from "../../../factories/serviceFactory";
55
import { NodeConfigService } from "../../../services/nodeConfigService";
6-
import { Bech32AddressHelper } from "../../../utils/bech32AddressHelper";
76
import { FormatHelper } from "../../../utils/formatHelper";
87
import { ReactComponent as DropdownIcon } from "./../../../assets/dropdown-arrow.svg";
98
import Bech32Address from "./Bech32Address";
@@ -71,10 +70,8 @@ class MigratedFund extends Component<MigratedFundProps, MigratedFundState> {
7170
{this.props.fund.address.type === ED25519_ADDRESS_TYPE && (
7271
<Bech32Address
7372
activeLinks={true}
74-
addressDetails={Bech32AddressHelper.buildAddress(
75-
this.props.fund.address.pubKeyHash,
76-
this._bech32Hrp
77-
)}
73+
showHexAddress={true}
74+
address={this.props.fund.address}
7875
/>
7976
)}
8077
</div>

src/app/components/tangle/Output.tsx

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { BASIC_OUTPUT_TYPE, ALIAS_OUTPUT_TYPE, FOUNDRY_OUTPUT_TYPE, NFT_OUTPUT_TYPE, TREASURY_OUTPUT_TYPE, IOutputResponse, SIMPLE_TOKEN_SCHEME_TYPE } from "@iota/iota.js";
1+
import { Blake2b } from "@iota/crypto.js";
2+
import { BASIC_OUTPUT_TYPE, ALIAS_OUTPUT_TYPE, FOUNDRY_OUTPUT_TYPE, NFT_OUTPUT_TYPE, TREASURY_OUTPUT_TYPE, IOutputResponse, SIMPLE_TOKEN_SCHEME_TYPE, ALIAS_ADDRESS_TYPE, NFT_ADDRESS_TYPE } from "@iota/iota.js";
3+
import { Converter, HexHelper } from "@iota/util.js";
4+
import bigInt from "big-integer";
25
import classNames from "classnames";
36
import React, { Component, ReactNode } from "react";
47
import { Link } from "react-router-dom";
@@ -7,6 +10,7 @@ import { FormatHelper } from "../../../utils/formatHelper";
710
import { NameHelper } from "../../../utils/nameHelper";
811
import MessageButton from "../layout/MessageButton";
912
import { ReactComponent as DropdownIcon } from "./../../../assets/dropdown-arrow.svg";
13+
import Bech32Address from "./Bech32Address";
1014
import FeatureBlock from "./FeatureBlock";
1115
import { OutputProps } from "./OutputProps";
1216
import { OutputState } from "./OutputState";
@@ -152,12 +156,16 @@ class Output extends Component<OutputProps, OutputState> {
152156

153157
{this.state.output.type === ALIAS_OUTPUT_TYPE && (
154158
<React.Fragment>
155-
<div className="card--label">
156-
Alias id:
157-
</div>
158-
<div className="card--value row">
159-
{this.state.output.aliasId}
160-
</div>
159+
<Bech32Address
160+
activeLinks={true}
161+
showHexAddress={false}
162+
address={
163+
{
164+
aliasId: this.resolveId(this.state.output.aliasId),
165+
type: ALIAS_ADDRESS_TYPE
166+
}
167+
}
168+
/>
161169
<div className="card--label">
162170
State index:
163171
</div>
@@ -180,14 +188,16 @@ class Output extends Component<OutputProps, OutputState> {
180188
)}
181189

182190
{this.state.output.type === NFT_OUTPUT_TYPE && (
183-
<React.Fragment>
184-
<div className="card--label">
185-
Nft id:
186-
</div>
187-
<div className="card--value row">
188-
{this.state.output.nftId}
189-
</div>
190-
</React.Fragment>
191+
<Bech32Address
192+
activeLinks={true}
193+
showHexAddress={false}
194+
address={
195+
{
196+
nftId: this.resolveId(this.state.output.nftId),
197+
type: NFT_ADDRESS_TYPE
198+
}
199+
}
200+
/>
191201
)}
192202

193203
{this.state.output.type === FOUNDRY_OUTPUT_TYPE && (
@@ -294,6 +304,19 @@ class Output extends Component<OutputProps, OutputState> {
294304
private isOutputResponse(object: unknown): object is IOutputResponse {
295305
return Object.prototype.hasOwnProperty.call(object, "messageId");
296306
}
307+
308+
/**
309+
* Check if id is all 0 because it hasn't moved and compute it as a hash of the outputId.
310+
* @param id The id to resolve.
311+
* @returns The correct id.
312+
*/
313+
private resolveId(id: string): string {
314+
return !HexHelper.toBigInt256(id).eq(bigInt.zero)
315+
? id
316+
: HexHelper.addPrefix(Converter.bytesToHex(
317+
Blake2b.sum256(Converter.hexToBytes(HexHelper.stripPrefix(this.props.outputId)))
318+
));
319+
}
297320
}
298321

299322
export default Output;

src/app/components/tangle/OutputProps.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export interface OutputProps {
66
*/
77
index: number;
88

9+
/**
10+
* The output id.
11+
*/
12+
outputId: string;
13+
914
/**
1015
* The output to display.
1116
*/

0 commit comments

Comments
 (0)