From 417d448aca06890fe509c7bcd4388f2c29b1a1f8 Mon Sep 17 00:00:00 2001 From: Chris Li <chris@mystenlabs.com> Date: Sun, 5 Mar 2023 00:01:07 -0500 Subject: [PATCH] Add support for TS-SDK + Explorer --- .changeset/clean-goats-dress.md | 5 + Cargo.lock | 18 +- .../top-validators-card/TopValidatorsCard.tsx | 8 +- .../components/validator/ValidatorMeta.tsx | 12 +- .../components/validator/ValidatorStats.tsx | 6 +- .../src/components/validator/calculateAPY.ts | 8 +- .../src/pages/validator/ValidatorDetails.tsx | 7 +- .../src/pages/validators/Validators.tsx | 22 +-- .../src/unit_tests/rpc_server_tests.rs | 6 +- crates/sui-sdk/src/apis.rs | 7 +- sdk/typescript/src/types/dynamic_fields.ts | 3 +- sdk/typescript/src/types/validator.ts | 157 ++++++++---------- sdk/typescript/test/e2e/governance.test.ts | 2 +- sdk/typescript/test/e2e/txn-builder.test.ts | 4 +- .../test/e2e/txn-serializer.test.ts | 4 +- sdk/typescript/test/e2e/utils/setup.ts | 1 - 16 files changed, 118 insertions(+), 152 deletions(-) create mode 100644 .changeset/clean-goats-dress.md diff --git a/.changeset/clean-goats-dress.md b/.changeset/clean-goats-dress.md new file mode 100644 index 0000000000000..415b0c85260df --- /dev/null +++ b/.changeset/clean-goats-dress.md @@ -0,0 +1,5 @@ +--- +"@mysten/sui.js": minor +--- + +Update schema for `SuiSystemState` and `DelegatedStake` diff --git a/Cargo.lock b/Cargo.lock index adcf0d6766abb..b91ab2ee41dec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7125,15 +7125,6 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "reqwest" version = "0.11.13" @@ -9620,16 +9611,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys", ] [[package]] diff --git a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx index 5ffc1632b280e..01e58b1856848 100644 --- a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx +++ b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx @@ -21,9 +21,9 @@ const NUMBER_OF_VALIDATORS = 10; export function processValidators(set: Validator[]) { return set.map((av) => ({ name: av.metadata.name, - address: av.metadata.sui_address, - stake: av.staking_pool.sui_balance, - logo: av.metadata.image_url, + address: av.metadata.suiAddress, + stake: av.stakingPool.suiBalance, + logo: av.metadata.imageUrl, })); } @@ -94,7 +94,7 @@ export function TopValidatorsCard({ limit, showIcon }: TopValidatorsCardProps) { () => data ? validatorsTable( - data.validators.active_validators, + data.validators.activeValidators, limit, showIcon ) diff --git a/apps/explorer/src/components/validator/ValidatorMeta.tsx b/apps/explorer/src/components/validator/ValidatorMeta.tsx index 941c8971fea83..52e2a56b69bb9 100644 --- a/apps/explorer/src/components/validator/ValidatorMeta.tsx +++ b/apps/explorer/src/components/validator/ValidatorMeta.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ArrowUpRight12 } from '@mysten/icons'; -import { toB64, type Validator } from '@mysten/sui.js'; +import { type Validator } from '@mysten/sui.js'; import { StakeButton } from './StakeButton'; @@ -17,14 +17,12 @@ type ValidatorMetaProps = { }; export function ValidatorMeta({ validatorData }: ValidatorMetaProps) { - const validatorPublicKey = toB64( - new Uint8Array(validatorData.metadata.protocol_pubkey_bytes) - ); + const validatorPublicKey = validatorData.metadata.protocolPubkeyBytes; const validatorName = validatorData.metadata.name; - const logo = validatorData.metadata.image_url; + const logo = validatorData.metadata.imageUrl; const description = validatorData.metadata.description; - const projectUrl = validatorData.metadata.project_url; + const projectUrl = validatorData.metadata.projectUrl; return ( <> @@ -69,7 +67,7 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps) { </DescriptionItem> <DescriptionItem title="Address"> <AddressLink - address={validatorData.metadata.sui_address} + address={validatorData.metadata.suiAddress} noTruncate /> </DescriptionItem> diff --git a/apps/explorer/src/components/validator/ValidatorStats.tsx b/apps/explorer/src/components/validator/ValidatorStats.tsx index 5b87fe2dbf65a..ba58659566432 100644 --- a/apps/explorer/src/components/validator/ValidatorStats.tsx +++ b/apps/explorer/src/components/validator/ValidatorStats.tsx @@ -33,9 +33,9 @@ export function ValidatorStats({ () => calculateAPY(validatorData, +epoch), [validatorData, epoch] ); - const totalStake = +validatorData.staking_pool.sui_balance; - const commission = +validatorData.commission_rate / 100; - const rewardsPoolBalance = +validatorData.staking_pool.rewards_pool; + const totalStake = +validatorData.stakingPool.suiBalance; + const commission = +validatorData.commissionRate / 100; + const rewardsPoolBalance = +validatorData.stakingPool.rewardsPool; return ( <div className="flex flex-col items-stretch gap-5 md:flex-row"> diff --git a/apps/explorer/src/components/validator/calculateAPY.ts b/apps/explorer/src/components/validator/calculateAPY.ts index 6a4e27425cc85..89d9563d16d6c 100644 --- a/apps/explorer/src/components/validator/calculateAPY.ts +++ b/apps/explorer/src/components/validator/calculateAPY.ts @@ -8,13 +8,13 @@ import { roundFloat } from '~/utils/roundFloat'; const APY_DECIMALS = 4; export function calculateAPY(validator: Validator, epoch: number) { - const { sui_balance, starting_epoch, pool_token_balance } = - validator.staking_pool; + const { suiBalance, startingEpoch, poolTokenBalance } = + validator.stakingPool; - const num_epochs_participated = +epoch - +starting_epoch; + const num_epochs_participated = +epoch - +startingEpoch; const apy = Math.pow( - 1 + (+sui_balance - +pool_token_balance) / +pool_token_balance, + 1 + (+suiBalance - +poolTokenBalance) / +poolTokenBalance, 365 / num_epochs_participated ) - 1; diff --git a/apps/explorer/src/pages/validator/ValidatorDetails.tsx b/apps/explorer/src/pages/validator/ValidatorDetails.tsx index f8291533ac26d..5455fc28bb067 100644 --- a/apps/explorer/src/pages/validator/ValidatorDetails.tsx +++ b/apps/explorer/src/pages/validator/ValidatorDetails.tsx @@ -20,14 +20,13 @@ function ValidatorDetails() { const validatorData = useMemo(() => { if (!data) return null; return ( - data.validators.active_validators.find( - (av) => av.metadata.sui_address === id + data.validators.activeValidators.find( + (av) => av.metadata.suiAddress === id ) || null ); }, [id, data]); - const numberOfValidators = - data?.validators.active_validators.length ?? null; + const numberOfValidators = data?.validators.activeValidators.length ?? null; const { data: validatorEvents, isLoading: validatorsEventsLoading } = useGetValidatorsEvents({ diff --git a/apps/explorer/src/pages/validators/Validators.tsx b/apps/explorer/src/pages/validators/Validators.tsx index a898e2eff715d..6c3f1b9242282 100644 --- a/apps/explorer/src/pages/validators/Validators.tsx +++ b/apps/explorer/src/pages/validators/Validators.tsx @@ -35,24 +35,24 @@ function validatorsTableData( return { data: validators.map((validator) => { const validatorName = validator.metadata.name; - const totalStake = validator.staking_pool.sui_balance; - const img = validator.metadata.image_url; + const totalStake = validator.stakingPool.suiBalance; + const img = validator.metadata.imageUrl; const event = getValidatorMoveEvent( validatorsEvents, - validator.metadata.sui_address + validator.metadata.suiAddress ); return { name: { name: validatorName, - logo: validator.metadata.image_url, + logo: validator.metadata.imageUrl, }, stake: totalStake, apy: calculateAPY(validator, epoch), - commission: +validator.commission_rate / 100, + commission: +validator.commissionRate / 100, img: img, - address: validator.metadata.sui_address, + address: validator.metadata.suiAddress, lastReward: event?.fields.stake_rewards || 0, }; }), @@ -158,7 +158,7 @@ function ValidatorPageResult() { const { data, isLoading, isSuccess, isError } = useGetSystemObject(); const numberOfValidators = useMemo( - () => data?.validators.active_validators.length || null, + () => data?.validators.activeValidators.length || null, [data] ); @@ -173,17 +173,17 @@ function ValidatorPageResult() { const totalStaked = useMemo(() => { if (!data) return 0; - const validators = data.validators.active_validators; + const validators = data.validators.activeValidators; return validators.reduce( - (acc, cur) => acc + +cur.staking_pool.sui_balance, + (acc, cur) => acc + +cur.stakingPool.suiBalance, 0 ); }, [data]); const averageAPY = useMemo(() => { if (!data) return 0; - const validators = data.validators.active_validators; + const validators = data.validators.activeValidators; const validatorsApy = validators.map((av) => calculateAPY(av, +data.epoch) @@ -212,7 +212,7 @@ function ValidatorPageResult() { const validatorsTable = useMemo(() => { if (!data || !validatorEvents) return null; - const validators = data.validators.active_validators; + const validators = data.validators.activeValidators; return validatorsTableData( validators, diff --git a/crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs b/crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs index 8b4bebfd6cf97..629fe5af1be1b 100644 --- a/crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs +++ b/crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs @@ -13,12 +13,12 @@ use sui_config::SUI_KEYSTORE_FILENAME; use sui_framework_build::compiled_package::BuildConfig; use sui_json::SuiJsonValue; +use sui_json_rpc_types::SuiObjectInfo; use sui_json_rpc_types::{ - Balance, CoinPage, DelegatedStake, DelegationStatus, SuiObjectResponse, SuiCoinMetadata, - SuiEvent, SuiExecutionStatus, SuiObjectInfo, SuiTBlsSignObjectCommitmentType, + Balance, CoinPage, DelegatedStake, DelegationStatus, SuiCoinMetadata, SuiEvent, + SuiExecutionStatus, SuiObjectDataOptions, SuiObjectResponse, SuiTBlsSignObjectCommitmentType, SuiTransactionResponse, TransactionBytes, }; -use sui_json_rpc_types::{SuiObjectDataOptions, SuiObjectInfo}; use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; use sui_types::balance::Supply; use sui_types::base_types::ObjectID; diff --git a/crates/sui-sdk/src/apis.rs b/crates/sui-sdk/src/apis.rs index 5033e0179fdea..d0a9aba5937de 100644 --- a/crates/sui-sdk/src/apis.rs +++ b/crates/sui-sdk/src/apis.rs @@ -14,10 +14,9 @@ use std::time::{Duration, Instant}; use sui_json_rpc::api::GovernanceReadApiClient; use sui_json_rpc_types::{ Balance, Checkpoint, CheckpointId, Coin, CoinPage, DelegatedStake, DryRunTransactionResponse, - DynamicFieldPage, EventPage, GetRawObjectDataResponse, SuiCoinMetadata, SuiEventEnvelope, - SuiEventFilter, SuiMoveNormalizedModule, SuiObjectDataOptions, SuiObjectInfo, - SuiObjectResponse, SuiPastObjectResponse, SuiSystemStateRpc, SuiTransactionResponse, - TransactionsPage, + DynamicFieldPage, EventPage, SuiCoinMetadata, SuiEventEnvelope, SuiEventFilter, + SuiMoveNormalizedModule, SuiObjectDataOptions, SuiObjectInfo, SuiObjectResponse, + SuiPastObjectResponse, SuiSystemStateRpc, SuiTransactionResponse, TransactionsPage, }; use sui_types::balance::Supply; use sui_types::base_types::{ diff --git a/sdk/typescript/src/types/dynamic_fields.ts b/sdk/typescript/src/types/dynamic_fields.ts index 591f8ba63fd66..4980d8cf0a66f 100644 --- a/sdk/typescript/src/types/dynamic_fields.ts +++ b/sdk/typescript/src/types/dynamic_fields.ts @@ -26,7 +26,8 @@ export const DynamicFieldName = object({ export type DynamicFieldName = Infer<typeof DynamicFieldName>; export const DynamicFieldInfo = object({ - name: union([DynamicFieldName, string()]), + name: DynamicFieldName, + bcsName: string(), type: DynamicFieldType, objectType: string(), objectId: ObjectId, diff --git a/sdk/typescript/src/types/validator.ts b/sdk/typescript/src/types/validator.ts index 511277229ce39..07e8c9dc7ddc4 100644 --- a/sdk/typescript/src/types/validator.ts +++ b/sdk/typescript/src/types/validator.ts @@ -14,33 +14,33 @@ import { tuple, optional, } from 'superstruct'; -import { SuiAddress } from './common'; -import { AuthorityName } from './transactions'; +import { ObjectId, SuiAddress } from './common'; +import { AuthorityName, EpochId } from './transactions'; /* -------------- Types for the SuiSystemState Rust definition -------------- */ export const ValidatorMetaData = object({ - sui_address: SuiAddress, - protocol_pubkey_bytes: array(number()), - network_pubkey_bytes: array(number()), - worker_pubkey_bytes: array(number()), - proof_of_possession_bytes: array(number()), + suiAddress: SuiAddress, + protocolPubkeyBytes: string(), + networkPubkeyBytes: string(), + workerPubkeyBytes: string(), + proofOfPossessionBytes: string(), name: string(), description: string(), - image_url: string(), - project_url: string(), - p2p_address: array(number()), - net_address: array(number()), - primary_address: array(number()), - worker_address: array(number()), - next_epoch_protocol_pubkey_bytes: nullable(array(number())), - next_epoch_proof_of_possession: nullable(array(number())), - next_epoch_network_pubkey_bytes: nullable(array(number())), - next_epoch_worker_pubkey_bytes: nullable(array(number())), - next_epoch_net_address: nullable(array(number())), - next_epoch_p2p_address: nullable(array(number())), - next_epoch_primary_address: nullable(array(number())), - next_epoch_worker_address: nullable(array(number())), + imageUrl: string(), + projectUrl: string(), + p2pAddress: string(), + netAddress: string(), + primaryAddress: string(), + workerAddress: string(), + nextEpochProtocolPubkeyBytes: nullable(string()), + nextEpochProofOfPossession: nullable(string()), + nextEpochNetworkPubkeyBytes: nullable(string()), + nextEpochWorkerPubkeyBytes: nullable(string()), + nextEpochNetAddress: nullable(string()), + nextEpochP2pAddress: nullable(string()), + nextEpochPrimaryAddress: nullable(string()), + nextEpochWorkerAddress: nullable(string()), }); export type DelegatedStake = Infer<typeof DelegatedStake>; @@ -53,50 +53,25 @@ export const Balance = object({ value: number(), }); -export const StakedSui = object({ - id: object({ - id: string(), - }), - pool_id: string(), - validator_address: string(), - delegation_request_epoch: number(), - principal: Balance, - sui_token_lock: union([number(), literal(null)]), -}); - -export const ActiveFields = object({ - id: object({ - id: string(), - }), - staked_sui_id: SuiAddress, - principal_sui_amount: number(), - pool_tokens: Balance, -}); - -export const ActiveDelegationStatus = object({ - Active: ActiveFields, +export const DelegationObject = object({ + stakedSuiId: ObjectId, + delegationRequestEpoch: EpochId, + principal: number(), + tokenLock: nullable(EpochId), + status: union([literal('Active'), literal('Pending')]), + estimatedReward: optional(number()), }); export const DelegatedStake = object({ - staked_sui: StakedSui, - delegation_status: union([literal('Pending'), ActiveDelegationStatus]), -}); - -export const ParametersFields = object({ - max_validator_candidate_count: string(), - min_validator_stake: string(), - storage_gas_price: optional(string()), -}); - -export const Parameters = object({ - type: string(), - fields: ParametersFields, + validatorAddress: SuiAddress, + stakingPool: ObjectId, + delegations: array(DelegationObject), }); export const StakeSubsidyFields = object({ balance: object({ value: number() }), - current_epoch_amount: number(), - epoch_counter: number(), + currentEpochAmount: number(), + epochCounter: number(), }); export const StakeSubsidy = object({ @@ -126,19 +101,19 @@ export const Contents = object({ }); export const DelegationStakingPoolFields = object({ - exchange_rates: object({ + exchangeRates: object({ id: string(), size: number(), }), id: string(), - pending_delegation: number(), - pending_pool_token_withdraw: number(), - pending_total_sui_withdraw: number(), - pool_token_balance: number(), - rewards_pool: object({ value: number() }), - starting_epoch: number(), - deactivation_epoch: object({ vec: array() }), - sui_balance: number(), + pendingDelegation: number(), + pendingPoolTokenWithdraw: number(), + pendingTotalSuiWithdraw: number(), + poolTokenBalance: number(), + rewardsPool: object({ value: number() }), + startingEpoch: number(), + deactivationEpoch: object({ vec: array() }), + suiBalance: number(), }); export const DelegationStakingPool = object({ @@ -153,21 +128,21 @@ export const CommitteeInfo = object({ }); export const SystemParameters = object({ - min_validator_stake: number(), - max_validator_candidate_count: number(), - governance_start_epoch: number(), - storage_gas_price: optional(number()), + minValidatorStake: number(), + maxValidatorCandidateCount: number(), + governanceStartEpoch: number(), + storageGasPrice: optional(number()), }); export const Validator = object({ metadata: ValidatorMetaData, - voting_power: number(), - gas_price: number(), - staking_pool: DelegationStakingPoolFields, - commission_rate: number(), - next_epoch_stake: number(), - next_epoch_gas_price: number(), - next_epoch_commission_rate: number(), + votingPower: number(), + gasPrice: number(), + stakingPool: DelegationStakingPoolFields, + commissionRate: number(), + nextEpochStake: number(), + nextEpochGasPrice: number(), + nextEpochCommissionRate: number(), }); export type Validator = Infer<typeof Validator>; @@ -177,20 +152,20 @@ export const ValidatorPair = object({ }); export const ValidatorSet = object({ - total_stake: number(), - active_validators: array(Validator), - pending_validators: object({ + totalStake: number(), + activeValidators: array(Validator), + pendingValidators: object({ contents: object({ id: string(), size: number(), }), }), - pending_removals: array(number()), - staking_pool_mappings: object({ + pendingRemovals: array(number()), + stakingPoolMappings: object({ id: string(), size: number(), }), - inactive_pools: object({ + inactivePools: object({ id: string(), size: number(), }), @@ -198,15 +173,15 @@ export const ValidatorSet = object({ export const SuiSystemState = object({ epoch: number(), - protocol_version: number(), + protocolVersion: number(), validators: ValidatorSet, - storage_fund: Balance, + storageFund: Balance, parameters: SystemParameters, - reference_gas_price: number(), - validator_report_records: object({ contents: array() }), - stake_subsidy: StakeSubsidyFields, - safe_mode: boolean(), - epoch_start_timestamp_ms: optional(number()), + referenceGasPrice: number(), + validatorReportRecords: object({ contents: array() }), + stakeSubsidy: StakeSubsidyFields, + safeMode: boolean(), + epochStartTimestampMs: optional(number()), }); export type SuiSystemState = Infer<typeof SuiSystemState>; diff --git a/sdk/typescript/test/e2e/governance.test.ts b/sdk/typescript/test/e2e/governance.test.ts index a5e4733e287ab..e04084d64ae7d 100644 --- a/sdk/typescript/test/e2e/governance.test.ts +++ b/sdk/typescript/test/e2e/governance.test.ts @@ -76,7 +76,7 @@ async function addDelegation(signer: RawSigner) { await SuiSystemStateUtil.newRequestAddDelegationTxn( [coins[0].objectId], BigInt(DEFAULT_STAKED_AMOUNT), - validators[0].sui_address, + validators[0].suiAddress, DEFAULT_GAS_BUDGET, ), ); diff --git a/sdk/typescript/test/e2e/txn-builder.test.ts b/sdk/typescript/test/e2e/txn-builder.test.ts index 2ca3a3f0487e2..408c9f35cfdf0 100644 --- a/sdk/typescript/test/e2e/txn-builder.test.ts +++ b/sdk/typescript/test/e2e/txn-builder.test.ts @@ -92,7 +92,7 @@ describe.each([{ useLocalTxnBuilder: true }, { useLocalTxnBuilder: false }])( toolbox.address(), ); - const [{ sui_address: validator_address }] = + const [{ suiAddress: validatorAddress }] = await toolbox.getActiveValidators(); await validateTransaction(signer, { @@ -105,7 +105,7 @@ describe.each([{ useLocalTxnBuilder: true }, { useLocalTxnBuilder: false }])( arguments: [ SUI_SYSTEM_STATE_OBJECT_ID, coins[2].objectId, - validator_address, + validatorAddress, ], gasBudget: DEFAULT_GAS_BUDGET, gasPayment: coins[3].objectId, diff --git a/sdk/typescript/test/e2e/txn-serializer.test.ts b/sdk/typescript/test/e2e/txn-serializer.test.ts index 344304359070c..c814e4bffeaf0 100644 --- a/sdk/typescript/test/e2e/txn-serializer.test.ts +++ b/sdk/typescript/test/e2e/txn-serializer.test.ts @@ -133,7 +133,7 @@ describe('Transaction Serialization and deserialization', () => { toolbox.address(), ); - const [{ sui_address: validator_address }] = + const [{ suiAddress: validatorAddress }] = await toolbox.getActiveValidators(); const moveCall = { @@ -145,7 +145,7 @@ describe('Transaction Serialization and deserialization', () => { arguments: [ SUI_SYSTEM_STATE_OBJECT_ID, coins[2].objectId, - validator_address, + validatorAddress, ], gasOwner: toolbox.address(), gasBudget: DEFAULT_GAS_BUDGET, diff --git a/sdk/typescript/test/e2e/utils/setup.ts b/sdk/typescript/test/e2e/utils/setup.ts index b5eafe16d1c03..a5afb4115cdee 100644 --- a/sdk/typescript/test/e2e/utils/setup.ts +++ b/sdk/typescript/test/e2e/utils/setup.ts @@ -83,7 +83,6 @@ export async function publishPackage( tmp.setGracefulCleanup(); const tmpobj = tmp.dirSync({ unsafeCleanup: true }); - console.log('Dir: ', tmpobj.name); const compiledModules = JSON.parse( execSync(