Skip to content

Commit

Permalink
[explorer] Fix smart contract rendering (MystenLabs#1778)
Browse files Browse the repository at this point in the history
  • Loading branch information
666lcz authored May 4, 2022
1 parent 70701b9 commit f2a0e2b
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 15 deletions.
12 changes: 6 additions & 6 deletions explorer/client/src/components/ownedobjects/OwnedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

import React, { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { getObjectExistsResponse } from 'sui.js';
import { getObjectContent, getObjectExistsResponse } from 'sui.js';

import { DefaultRpcClient as rpc } from '../../utils/api/DefaultRpcClient';
import { parseImageURL } from '../../utils/objectUtils';
import { parseImageURL, parseObjectType } from '../../utils/objectUtils';
import { navigateWithUnknown } from '../../utils/searchUtil';
import {
findDataFromID,
Expand Down Expand Up @@ -82,16 +82,16 @@ function OwnedObjectAPI({ id }: { id: string }) {
.map(
(resp) => {
const info = getObjectExistsResponse(resp)!;
const contents = getObjectContent(resp);
const url = parseImageURL(info.object);
const balanceValue = (
typeof info.object.contents.fields
.balance === 'number'
? info.object.contents.fields.balance
typeof contents?.fields.balance === 'number'
? contents.fields.balance
: undefined
) as number;
return {
id: info.objectRef.objectId,
Type: info.object.contents.type,
Type: parseObjectType(info),
display: url
? processDisplayValue(url)
: undefined,
Expand Down
8 changes: 7 additions & 1 deletion explorer/client/src/pages/object-result/ObjectLoaded.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,13 @@ function ObjectLoaded({ data }: { data: DataType }) {
<Longtext
text={extractOwnerData(data.owner)}
category="unknown"
isLink={true}
// TODO: make this more elegant
isLink={
extractOwnerData(data.owner) !==
'Immutable' &&
extractOwnerData(data.owner) !==
'Shared'
}
/>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions explorer/client/src/pages/object-result/ObjectResultType.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { getMovePackageContent, getObjectContent, getObjectType } from 'sui.js';

import { type AddressOwner } from '../../utils/api/DefaultRpcClient';

import type {
Expand Down Expand Up @@ -47,16 +49,18 @@ export function translate(o: GetObjectInfoResponse): DataType {
case 'Exists': {
const {
objectRef: { objectId, version },
object: { contents, owner, tx_digest },
object: { owner, tx_digest },
} = details as ObjectExistsInfo;

return {
id: objectId,
version: version.toString(),
objType: contents['type'],
objType: getObjectType(o)!,
owner: parseOwner(owner),
data: {
contents: contents.fields,
contents:
getObjectContent(o)?.fields ??
getMovePackageContent(o)!,
tx_digest,
},
};
Expand Down
13 changes: 13 additions & 0 deletions explorer/client/src/utils/objectUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import type { ObjectExistsInfo } from 'sui.js';

export function parseImageURL(data: any): string {
if (data?.contents?.url?.fields) {
return data.contents.url.fields['url'];
Expand All @@ -11,3 +13,14 @@ export function parseImageURL(data: any): string {
}
return '';
}

export function parseObjectType(data: ObjectExistsInfo): string {
// TODO: define better naming and typing here
if (data.objectType === 'movePackage') {
return 'Move Package';
}
if (data.objectType === 'moveObject') {
return data.object.contents.type;
}
return 'unknown';
}
16 changes: 14 additions & 2 deletions sdk/typescript/src/index.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Generated type guards for "index.ts".
* WARNING: Do not manually change this file.
*/
import { Ed25519KeypairData, Keypair, PublicKeyInitData, PublicKeyData, SignedTransaction, TransactionResponse, TransferTransaction, TxnDataSerializer, TransactionDigest, SuiAddress, ObjectOwner, ObjectRef, ObjectContentField, ObjectContentFields, ObjectContent, SuiObject, ObjectExistsInfo, ObjectNotExistsInfo, ObjectStatus, ObjectType, GetOwnedObjectRefsResponse, GetObjectInfoResponse, ObjectDigest, ObjectId, SequenceNumber, RawObjectRef, Transfer, RawAuthoritySignInfo, TransactionKindName, SingleTransactionKind, TransactionKind, TransactionData, EpochId, AuthorityQuorumSignInfo, CertifiedTransaction, GasCostSummary, ExecutionStatusType, ExecutionStatus, ExecutionStatusDetail, OwnedObjectRef, TransactionEffects, TransactionEffectsResponse, GatewayTxSeqNumber, GetTxnDigestsResponse, MoveModulePublish, Event, StructTag, MoveTypeTag, MoveCall, MoveCallArg, EmptySignInfo, AuthorityName, AuthoritySignature } from "./index";
import { Ed25519KeypairData, Keypair, PublicKeyInitData, PublicKeyData, SignedTransaction, TransactionResponse, TransferTransaction, TxnDataSerializer, TransactionDigest, SuiAddress, ObjectOwner, ObjectRef, ObjectContentField, ObjectContentFields, ObjectContent, MovePackageContent, SuiObject, ObjectExistsInfo, ObjectNotExistsInfo, ObjectStatus, ObjectType, GetOwnedObjectRefsResponse, GetObjectInfoResponse, ObjectDigest, ObjectId, SequenceNumber, RawObjectRef, Transfer, RawAuthoritySignInfo, TransactionKindName, SingleTransactionKind, TransactionKind, TransactionData, EpochId, AuthorityQuorumSignInfo, CertifiedTransaction, GasCostSummary, ExecutionStatusType, ExecutionStatus, ExecutionStatusDetail, OwnedObjectRef, TransactionEffects, TransactionEffectsResponse, GatewayTxSeqNumber, GetTxnDigestsResponse, MoveModulePublish, Event, StructTag, MoveTypeTag, MoveCall, MoveCallArg, EmptySignInfo, AuthorityName, AuthoritySignature } from "./index";
import { BN } from "bn.js";

export function isEd25519KeypairData(obj: any, _argumentName?: string): obj is Ed25519KeypairData {
Expand Down Expand Up @@ -163,12 +163,24 @@ export function isObjectContent(obj: any, _argumentName?: string): obj is Object
)
}

export function isMovePackageContent(obj: any, _argumentName?: string): obj is MovePackageContent {
return (
(obj !== null &&
typeof obj === "object" ||
typeof obj === "function") &&
Object.entries<any>(obj)
.every(([key, value]) => (isTransactionResponse(value) as boolean &&
isTransactionResponse(key) as boolean))
)
}

export function isSuiObject(obj: any, _argumentName?: string): obj is SuiObject {
return (
(obj !== null &&
typeof obj === "object" ||
typeof obj === "function") &&
isObjectContent(obj.contents) as boolean &&
(isObjectContent(obj.contents) as boolean ||
isMovePackageContent(obj.contents) as boolean) &&
isObjectOwner(obj.owner) as boolean &&
isTransactionResponse(obj.tx_digest) as boolean
)
Expand Down
32 changes: 30 additions & 2 deletions sdk/typescript/src/types/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ export type ObjectContent = {
type: string;
};

export type MovePackageContent = Record<string, string>;

export type SuiObject = {
contents: ObjectContent;
contents: ObjectContent | MovePackageContent;
owner: ObjectOwner;
tx_digest: TransactionDigest;
};
Expand Down Expand Up @@ -69,8 +71,34 @@ export function getObjectExistsResponse(
: (resp.details as ObjectExistsInfo);
}

export function getObjectType(
resp: GetObjectInfoResponse
): 'moveObject' | 'movePackage' | undefined {
return getObjectExistsResponse(resp)?.objectType;
}

export function getObjectContent(
resp: GetObjectInfoResponse
): ObjectContent | undefined {
return getObjectExistsResponse(resp)?.object.contents;
const existsInfo = getObjectExistsResponse(resp);
if (existsInfo == null) {
return undefined;
}
const { object, objectType } = existsInfo;
return objectType === 'moveObject'
? (object.contents as ObjectContent)
: undefined;
}

export function getMovePackageContent(
resp: GetObjectInfoResponse
): MovePackageContent | undefined {
const existsInfo = getObjectExistsResponse(resp);
if (existsInfo == null) {
return undefined;
}
const { object, objectType } = existsInfo;
return objectType === 'movePackage'
? (object.contents as MovePackageContent)
: undefined;
}
19 changes: 19 additions & 0 deletions sdk/typescript/test/mocks/data/objects.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,24 @@
"tx_digest": "vU/KG88bjX8VgdNtflBjNUFNZAqYv2qMCwP9S0+tQRc="
}
}
},

"move_package": {
"status": "Exists",
"details": {
"objectRef": {
"objectId": "8070e826b3668a048a59a095de23ec26491ca2d9",
"version": 1,
"digest": "mpvRbMifZveAfw0wnss0EwtUhc0XgeTvQWO5V0vG790="
},
"objectType": "movePackage",
"object": {
"contents": {
"M1": "// Move bytecode v5\nmodule 8070e826b3668a048a59a095de23ec26491ca2d9.M1 {\nstruct Forge has store, key {\n\tid: VersionedID,\n\tswords_created: u64\n}\nstruct Sword has store, key {\n\tid: VersionedID,\n\tmagic: u64,\n\tstrength: u64\n}\n\ninit(loc0: &mut TxContext) {\nB0:\n\t0: CopyLoc[0](Arg0: &mut TxContext)\n\t1: Call[6](new_id(&mut TxContext): VersionedID)\n\t2: LdU64(0)\n\t3: Pack[0](Forge)\n\t4: StLoc[1](loc0: Forge)\n\t5: MoveLoc[1](loc0: Forge)\n\t6: MoveLoc[0](Arg0: &mut TxContext)\n\t7: FreezeRef\n\t8: Call[7](sender(&TxContext): address)\n\t9: Call[0](transfer<Forge>(Forge, address))\n\t10: Ret\n}\npublic magic(): u64 {\nB0:\n\t0: MoveLoc[0](Arg0: &Sword)\n\t1: ImmBorrowField[0](Sword.magic: u64)\n\t2: ReadRef\n\t3: Ret\n}\npublic strength(): u64 {\nB0:\n\t0: MoveLoc[0](Arg0: &Sword)\n\t1: ImmBorrowField[1](Sword.strength: u64)\n\t2: ReadRef\n\t3: Ret\n}\npublic(script) sword_create(loc0: &mut Forge) {\nB0:\n\t0: MoveLoc[4](Arg4: &mut TxContext)\n\t1: Call[6](new_id(&mut TxContext): VersionedID)\n\t2: MoveLoc[1](Arg1: u64)\n\t3: MoveLoc[2](Arg2: u64)\n\t4: Pack[1](Sword)\n\t5: StLoc[5](loc0: Sword)\n\t6: MoveLoc[5](loc0: Sword)\n\t7: MoveLoc[3](Arg3: address)\n\t8: Call[1](transfer<Sword>(Sword, address))\n\t9: CopyLoc[0](Arg0: &mut Forge)\n\t10: ImmBorrowField[2](Forge.swords_created: u64)\n\t11: ReadRef\n\t12: LdU64(1)\n\t13: Add\n\t14: MoveLoc[0](Arg0: &mut Forge)\n\t15: MutBorrowField[2](Forge.swords_created: u64)\n\t16: WriteRef\n\t17: Ret\n}\npublic(script) sword_transfer() {\nB0:\n\t0: MoveLoc[0](Arg0: Sword)\n\t1: MoveLoc[1](Arg1: address)\n\t2: Call[1](transfer<Sword>(Sword, address))\n\t3: Ret\n}\npublic swords_created(): u64 {\nB0:\n\t0: MoveLoc[0](Arg0: &Forge)\n\t1: ImmBorrowField[2](Forge.swords_created: u64)\n\t2: ReadRef\n\t3: Ret\n}\n}"
},
"owner": "Immutable",
"tx_digest": "Zy76499PkX9Rm4DEWEj5o1NSnLWqu/700Xfx+bd4qSc="
}
}
}
}
5 changes: 4 additions & 1 deletion sdk/typescript/test/types/objects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ describe('Test Objects Definition', () => {
it('Test against different object definitions', () => {
validate('coin');
validate('example_nft');
validate('move_package');
});
});

function validate(key: 'coin' | 'example_nft'): GetObjectInfoResponse {
function validate(
key: 'coin' | 'example_nft' | 'move_package'
): GetObjectInfoResponse {
const data = mockObjectData[key];
expect(isGetObjectInfoResponse(data)).toBeTruthy();
return data as GetObjectInfoResponse;
Expand Down

0 comments on commit f2a0e2b

Please sign in to comment.