From 7ed816d8db7ac75468faa235c09f147db5009034 Mon Sep 17 00:00:00 2001 From: jeff <113397187+cyberhorsey@users.noreply.github.com> Date: Fri, 26 May 2023 21:19:43 -0700 Subject: [PATCH] feat(status-page): updates for a3 (#13821) Co-authored-by: David Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com> --- packages/eventindexer/http/get_stats_test.go | 2 +- .../indexer/save_block_proven_event.go | 16 +- .../indexer/save_block_verified_event.go | 4 +- packages/eventindexer/indexer/subscribe.go | 167 +-- .../1666650701_create_stats_table.sql | 1 + packages/eventindexer/mock/stat_repository.go | 1 + packages/eventindexer/repo/stat.go | 1 + packages/eventindexer/repo/stat_test.go | 3 +- packages/eventindexer/stat.go | 1 + packages/relayer/indexer/subscribe.go | 3 + packages/status-page/.default.env | 1 + .../src/constants/abi/TaikoToken.ts | 1036 +++++++++++++++++ .../src/utils/buildStatusIndicators.ts | 97 +- .../src/utils/getAverageProofReward.ts | 10 - .../src/utils/getAverageProofTime.ts | 2 +- packages/status-page/src/utils/getBlockFee.ts | 11 - .../status-page/src/utils/getProofReward.ts | 14 - packages/status-page/src/utils/initConfig.ts | 2 + 18 files changed, 1242 insertions(+), 130 deletions(-) create mode 100644 packages/status-page/src/constants/abi/TaikoToken.ts delete mode 100644 packages/status-page/src/utils/getBlockFee.ts delete mode 100644 packages/status-page/src/utils/getProofReward.ts diff --git a/packages/eventindexer/http/get_stats_test.go b/packages/eventindexer/http/get_stats_test.go index 2664a02e0a7..08161dedd29 100644 --- a/packages/eventindexer/http/get_stats_test.go +++ b/packages/eventindexer/http/get_stats_test.go @@ -36,7 +36,7 @@ func Test_GetStats(t *testing.T) { "success", "0x123", http.StatusOK, - []string{`{"id":1,"averageProofTime":5,"averageProofReward":7,"numProofs":1}`}, + []string{`{"id":1,"averageProofTime":5,"averageProofReward":7,"numProofs":1,"numVerifiedBlocks":1}`}, }, } diff --git a/packages/eventindexer/indexer/save_block_proven_event.go b/packages/eventindexer/indexer/save_block_proven_event.go index e7b28767323..2c7eab4c0d6 100644 --- a/packages/eventindexer/indexer/save_block_proven_event.go +++ b/packages/eventindexer/indexer/save_block_proven_event.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" @@ -75,20 +74,25 @@ func (svc *Service) saveBlockProvenEvent( eventindexer.BlockProvenEventsProcessed.Inc() if event.Prover.Hex() != systemProver.Hex() && event.Prover.Hex() != oracleProver.Hex() { - if err := svc.updateAverageBlockTime(ctx, event); err != nil { - return errors.Wrap(err, "svc.updateAverageBlockTime") + if err := svc.updateAverageProofTime(ctx, event); err != nil { + return errors.Wrap(err, "svc.updateAverageProofTime") } } return nil } -func (svc *Service) updateAverageBlockTime(ctx context.Context, event *taikol1.TaikoL1BlockProven) error { +func (svc *Service) updateAverageProofTime(ctx context.Context, event *taikol1.TaikoL1BlockProven) error { block, err := svc.taikol1.GetBlock(nil, event.Id) if err != nil { return errors.Wrap(err, "svc.taikoL1.GetBlock") } + eventBlock, err := svc.ethClient.BlockByHash(ctx, event.Raw.BlockHash) + if err != nil { + return errors.Wrap(err, "svc.ethClient.BlockByHash") + } + stat, err := svc.statRepo.Find(ctx) if err != nil { return errors.Wrap(err, "svc.statRepo.Find") @@ -96,9 +100,9 @@ func (svc *Service) updateAverageBlockTime(ctx context.Context, event *taikol1.T proposedAt := block.ProposedAt - provenAt := time.Now().Unix() + provenAt := eventBlock.Time() - proofTime := uint64(provenAt) - proposedAt + proofTime := provenAt - proposedAt newAverageProofTime := calcNewAverage(stat.AverageProofTime, stat.NumProofs, proofTime) diff --git a/packages/eventindexer/indexer/save_block_verified_event.go b/packages/eventindexer/indexer/save_block_verified_event.go index e114541a7f1..6ee3fe92445 100644 --- a/packages/eventindexer/indexer/save_block_verified_event.go +++ b/packages/eventindexer/indexer/save_block_verified_event.go @@ -24,6 +24,8 @@ func (svc *Service) saveBlockVerifiedEvents( for { event := events.Event + log.Infof("new blockVerified event, blockId: %v", event.Id) + if event.Raw.Removed { continue } @@ -78,7 +80,7 @@ func (svc *Service) updateAverageBlockReward(ctx context.Context, event *taikol1 return errors.Wrap(err, "svc.statRepo.Find") } - newAverageProofReward := calcNewAverage(stat.AverageProofReward, stat.NumProofs, reward) + newAverageProofReward := calcNewAverage(stat.AverageProofReward, stat.NumVerifiedBlocks, reward) _, err = svc.statRepo.Save(ctx, eventindexer.SaveStatOpts{ ProofReward: &newAverageProofReward, diff --git a/packages/eventindexer/indexer/subscribe.go b/packages/eventindexer/indexer/subscribe.go index 6b33874e678..2d3a109c0bc 100644 --- a/packages/eventindexer/indexer/subscribe.go +++ b/packages/eventindexer/indexer/subscribe.go @@ -58,36 +58,40 @@ func (svc *Service) subscribeBlockProven(ctx context.Context, chainID *big.Int, log.Info("context finished") return case err := <-sub.Err(): + log.Errorf("sub.Err(): %v", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: - log.Infof("blockProvenEvent from subscription for prover %v", event.Prover.Hex()) + go func() { + log.Infof("blockProvenEvent from subscription for prover %v", event.Prover.Hex()) - if err := svc.saveBlockProvenEvent(ctx, chainID, event); err != nil { - eventindexer.BlockProvenEventsProcessedError.Inc() + if err := svc.saveBlockProvenEvent(ctx, chainID, event); err != nil { + eventindexer.BlockProvenEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveBlockProvenEvent: %v", err) + log.Errorf("svc.subscribe, svc.saveBlockProvenEvent: %v", err) - continue - } - - block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) - if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) - continue - } + return + } - if block.Height < event.Raw.BlockNumber { - err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ - Height: event.Raw.BlockNumber, - Hash: event.Raw.BlockHash, - ChainID: chainID, - }) + block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + return } - eventindexer.BlocksProcessed.Inc() - } + if block.Height < event.Raw.BlockNumber { + err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ + Height: event.Raw.BlockNumber, + Hash: event.Raw.BlockHash, + ChainID: chainID, + }) + if err != nil { + log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + return + } + + eventindexer.BlocksProcessed.Inc() + } + }() } } } @@ -114,48 +118,58 @@ func (svc *Service) subscribeBlockProposed(ctx context.Context, chainID *big.Int log.Info("context finished") return case err := <-sub.Err(): + log.Errorf("sub.Err(): %v", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: - log.Infof("blockProposedEvent from subscription") + go func() { + log.Infof("blockProposedEvent from subscription") + + tx, _, err := svc.ethClient.TransactionByHash(ctx, event.Raw.TxHash) + if err != nil { + log.Errorf("svc.ethClient.TransactionByHash: %v", err) - tx, _, err := svc.ethClient.TransactionByHash(ctx, event.Raw.TxHash) - if err != nil { - log.Errorf("svc.ethClient.TransactionByHash: %v", err) - } + return + } - sender, err := svc.ethClient.TransactionSender(ctx, tx, event.Raw.BlockHash, event.Raw.TxIndex) - if err != nil { - log.Errorf("svc.ethClient.TransactionSender: %v", err) - } + sender, err := svc.ethClient.TransactionSender(ctx, tx, event.Raw.BlockHash, event.Raw.TxIndex) + if err != nil { + log.Errorf("svc.ethClient.TransactionSender: %v", err) - log.Infof("blockProposed by: %v", sender.Hex()) + return + } - if err := svc.saveBlockProposedEvent(ctx, chainID, event, sender); err != nil { - eventindexer.BlockProposedEventsProcessedError.Inc() + log.Infof("blockProposed by: %v", sender.Hex()) - log.Errorf("svc.subscribe, svc.saveBlockProposedEvent: %v", err) + if err := svc.saveBlockProposedEvent(ctx, chainID, event, sender); err != nil { + eventindexer.BlockProposedEventsProcessedError.Inc() - continue - } + log.Errorf("svc.subscribe, svc.saveBlockProposedEvent: %v", err) - block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) - if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) - continue - } + return + } - if block.Height < event.Raw.BlockNumber { - err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ - Height: event.Raw.BlockNumber, - Hash: event.Raw.BlockHash, - ChainID: chainID, - }) + block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + + return } - eventindexer.BlocksProcessed.Inc() - } + if block.Height < event.Raw.BlockNumber { + err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ + Height: event.Raw.BlockNumber, + Hash: event.Raw.BlockHash, + ChainID: chainID, + }) + if err != nil { + log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + + return + } + + eventindexer.BlocksProcessed.Inc() + } + }() } } } @@ -167,6 +181,7 @@ func (svc *Service) subscribeBlockVerified(ctx context.Context, chainID *big.Int if err != nil { log.Errorf("svc.taikoL1.WatchBlockVerified: %v", err) } + log.Info("resubscribing to BlockVerified events") return svc.taikol1.WatchBlockVerified(&bind.WatchOpts{ @@ -182,35 +197,39 @@ func (svc *Service) subscribeBlockVerified(ctx context.Context, chainID *big.Int log.Info("context finished") return case err := <-sub.Err(): + log.Errorf("sub.Err(): %v", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: - log.Infof("blockVerifiedEvent from subscription") - - if err := svc.saveBlockVerifiedEvent(ctx, chainID, event); err != nil { - eventindexer.BlockVerifiedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveBlockProvenEvent: %v", err) - - continue - } - - block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) - if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) - continue - } - - if block.Height < event.Raw.BlockNumber { - err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ - Height: event.Raw.BlockNumber, - Hash: event.Raw.BlockHash, - ChainID: chainID, - }) + go func() { + log.Infof("blockVerifiedEvent from subscription") + + if err := svc.saveBlockVerifiedEvent(ctx, chainID, event); err != nil { + eventindexer.BlockVerifiedEventsProcessedError.Inc() + log.Errorf("svc.subscribe, svc.saveBlockVerifiedEvent: %v", err) + + return + } + + block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + return } - eventindexer.BlocksProcessed.Inc() - } + if block.Height < event.Raw.BlockNumber { + err = svc.blockRepo.Save(eventindexer.SaveBlockOpts{ + Height: event.Raw.BlockNumber, + Hash: event.Raw.BlockHash, + ChainID: chainID, + }) + if err != nil { + log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + return + } + + eventindexer.BlocksProcessed.Inc() + } + }() } } } diff --git a/packages/eventindexer/migrations/1666650701_create_stats_table.sql b/packages/eventindexer/migrations/1666650701_create_stats_table.sql index f4376afc0c6..3d3c9c5f447 100644 --- a/packages/eventindexer/migrations/1666650701_create_stats_table.sql +++ b/packages/eventindexer/migrations/1666650701_create_stats_table.sql @@ -5,6 +5,7 @@ CREATE TABLE IF NOT EXISTS stats ( average_proof_time int NOT NULL DEFAULT 0, average_proof_reward int NOT NULL DEFAULT 0, num_proofs int NOT NULL default 0, + num_verified_blocks int NOT NULL default 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP , updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); diff --git a/packages/eventindexer/mock/stat_repository.go b/packages/eventindexer/mock/stat_repository.go index 21923fdd33f..4645af5652a 100644 --- a/packages/eventindexer/mock/stat_repository.go +++ b/packages/eventindexer/mock/stat_repository.go @@ -19,6 +19,7 @@ func (r *StatRepository) Save(ctx context.Context, opts eventindexer.SaveStatOpt AverageProofTime: *opts.ProofTime, AverageProofReward: *opts.ProofReward, NumProofs: 1, + NumVerifiedBlocks: 1, } return r.stats, nil diff --git a/packages/eventindexer/repo/stat.go b/packages/eventindexer/repo/stat.go index 93a59edbadc..711091bd036 100644 --- a/packages/eventindexer/repo/stat.go +++ b/packages/eventindexer/repo/stat.go @@ -32,6 +32,7 @@ func (r *StatRepository) Save(ctx context.Context, opts eventindexer.SaveStatOpt } if opts.ProofReward != nil { + s.NumVerifiedBlocks++ s.AverageProofReward = *opts.ProofReward } diff --git a/packages/eventindexer/repo/stat_test.go b/packages/eventindexer/repo/stat_test.go index f962fd79c1f..1a5d4364eb7 100644 --- a/packages/eventindexer/repo/stat_test.go +++ b/packages/eventindexer/repo/stat_test.go @@ -42,7 +42,7 @@ func TestIntegration_Stat_Save(t *testing.T) { } } -func TestIntegration_Event_Find(t *testing.T) { +func TestIntegration_Stat_Find(t *testing.T) { db, close, err := testMysql(t) assert.Equal(t, nil, err) @@ -71,6 +71,7 @@ func TestIntegration_Event_Find(t *testing.T) { AverageProofReward: 4, AverageProofTime: 0, NumProofs: 0, + NumVerifiedBlocks: 1, }, nil, }, diff --git a/packages/eventindexer/stat.go b/packages/eventindexer/stat.go index 7927adb812b..57dc57ff1f5 100644 --- a/packages/eventindexer/stat.go +++ b/packages/eventindexer/stat.go @@ -12,6 +12,7 @@ type Stat struct { AverageProofTime uint64 `json:"averageProofTime"` AverageProofReward uint64 `json:"averageProofReward"` NumProofs uint64 `json:"numProofs"` + NumVerifiedBlocks uint64 `json:"numVerifiedBlocks"` } // SaveStatOpts diff --git a/packages/relayer/indexer/subscribe.go b/packages/relayer/indexer/subscribe.go index 1a87f5e2605..33351b68c0c 100644 --- a/packages/relayer/indexer/subscribe.go +++ b/packages/relayer/indexer/subscribe.go @@ -68,11 +68,13 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, if err != nil { log.Errorf("svc.subscribe, svc.handleEvent: %v", err) + return } block, err := svc.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, chainID) if err != nil { log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessedForEvent: %v", err) + return } if block.Height < event.Raw.BlockNumber { @@ -84,6 +86,7 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, }) if err != nil { log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + return } relayer.BlocksProcessed.Inc() diff --git a/packages/status-page/.default.env b/packages/status-page/.default.env index ff979910cfc..b9f4cc90525 100644 --- a/packages/status-page/.default.env +++ b/packages/status-page/.default.env @@ -2,6 +2,7 @@ VITE_NODE_ENV=production VITE_L1_RPC_URL="https://l1rpc.internal.taiko.xyz" VITE_L2_RPC_URL="https://l2rpc.internal.taiko.xyz" VITE_L3_RPC_URL="https://l2rpc.internal.taiko.xyz" +VITE_TAIKO_TOKEN_ADDRESS="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" VITE_L2_TAIKO_L2_ADDRESS="0x1000777700000000000000000000000000000001" VITE_L2_TAIKO_L1_ADDRESS="0x0B306BF915C4d645ff596e518fAf3F9669b97016" VITE_L3_TAIKO_L2_ADDRESS="0x1000777700000000000000000000000000000001" diff --git a/packages/status-page/src/constants/abi/TaikoToken.ts b/packages/status-page/src/constants/abi/TaikoToken.ts new file mode 100644 index 00000000000..a6cf40a5f78 --- /dev/null +++ b/packages/status-page/src/constants/abi/TaikoToken.ts @@ -0,0 +1,1036 @@ +export default [ + { + inputs: [], + name: "RESOLVER_DENIED", + type: "error", + }, + { + inputs: [], + name: "RESOLVER_INVALID_ADDR", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "chainId", + type: "uint256", + }, + { + internalType: "bytes32", + name: "name", + type: "bytes32", + }, + ], + name: "RESOLVER_ZERO_ADDR", + type: "error", + }, + { + inputs: [], + name: "TKO_INVALID_ADDR", + type: "error", + }, + { + inputs: [], + name: "TKO_INVALID_PREMINT_PARAMS", + type: "error", + }, + { + inputs: [], + name: "TKO_MINT_DISALLOWED", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "addressManager", + type: "address", + }, + ], + name: "AddressManagerChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Burn", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "fromDelegate", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "toDelegate", + type: "address", + }, + ], + name: "DelegateChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "delegate", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "previousBalance", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newBalance", + type: "uint256", + }, + ], + name: "DelegateVotesChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint8", + name: "version", + type: "uint8", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Mint", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "Snapshot", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "addressManager", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "allowance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint256", + name: "snapshotId", + type: "uint256", + }, + ], + name: "balanceOfAt", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "burnFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint32", + name: "pos", + type: "uint32", + }, + ], + name: "checkpoints", + outputs: [ + { + components: [ + { + internalType: "uint32", + name: "fromBlock", + type: "uint32", + }, + { + internalType: "uint224", + name: "votes", + type: "uint224", + }, + ], + internalType: "struct ERC20VotesUpgradeable.Checkpoint", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [ + { + internalType: "uint8", + name: "", + type: "uint8", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "subtractedValue", + type: "uint256", + }, + ], + name: "decreaseAllowance", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "delegatee", + type: "address", + }, + ], + name: "delegate", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "delegatee", + type: "address", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + internalType: "uint8", + name: "v", + type: "uint8", + }, + { + internalType: "bytes32", + name: "r", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + ], + name: "delegateBySig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "delegates", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + ], + name: "getPastTotalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + ], + name: "getPastVotes", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "getVotes", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "addedValue", + type: "uint256", + }, + ], + name: "increaseAllowance", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_addressManager", + type: "address", + }, + { + internalType: "string", + name: "_name", + type: "string", + }, + { + internalType: "string", + name: "_symbol", + type: "string", + }, + { + internalType: "address[]", + name: "_premintRecipients", + type: "address[]", + }, + { + internalType: "uint256[]", + name: "_premintAmounts", + type: "uint256[]", + }, + ], + name: "init", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "nonces", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "numCheckpoints", + outputs: [ + { + internalType: "uint32", + name: "", + type: "uint32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + { + internalType: "uint8", + name: "v", + type: "uint8", + }, + { + internalType: "bytes32", + name: "r", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "chainId", + type: "uint256", + }, + { + internalType: "bytes32", + name: "name", + type: "bytes32", + }, + { + internalType: "bool", + name: "allowZeroAddress", + type: "bool", + }, + ], + name: "resolve", + outputs: [ + { + internalType: "address payable", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "name", + type: "bytes32", + }, + { + internalType: "bool", + name: "allowZeroAddress", + type: "bool", + }, + ], + name: "resolve", + outputs: [ + { + internalType: "address payable", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newAddressManager", + type: "address", + }, + ], + name: "setAddressManager", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "snapshot", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "snapshotId", + type: "uint256", + }, + ], + name: "totalSupplyAt", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "transfer", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "transferFrom", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; diff --git a/packages/status-page/src/utils/buildStatusIndicators.ts b/packages/status-page/src/utils/buildStatusIndicators.ts index df42a58f72c..62ad179908a 100644 --- a/packages/status-page/src/utils/buildStatusIndicators.ts +++ b/packages/status-page/src/utils/buildStatusIndicators.ts @@ -1,10 +1,10 @@ import { BigNumber, Contract, ethers } from "ethers"; +import TaikoToken from "../constants/abi/TaikoToken"; import TaikoL1 from "../constants/abi/TaikoL1"; import type { Status, StatusIndicatorProp } from "../domain/status"; import { getAvailableSlots } from "./getAvailableSlots"; -import { getAverageProofReward } from "./getAverageProofReward"; +import type { StatsResponse } from "./getAverageProofReward"; import { getAverageProofTime } from "./getAverageProofTime"; -import { getBlockFee } from "./getBlockFee"; import { getEthDeposits } from "./getEthDeposits"; import { getGasPrice } from "./getGasPrice"; import { getLastVerifiedBlockId } from "./getLastVerifiedBlockId"; @@ -15,11 +15,13 @@ import { getNumProposers } from "./getNumProposers"; import { getNumProvers } from "./getNumProvers"; import { getPendingBlocks } from "./getPendingBlocks"; import { getPendingTransactions } from "./getPendingTransactions"; -import { getProofReward } from "./getProofReward"; import { getQueuedTransactions } from "./getQueuedTransactions"; -import { getStateVariables } from "./getStateVariables"; import type { initConfig } from "./initConfig"; +import { truncateString } from "./truncateString"; import { watchHeaderSynced } from "./watchHeaderSynced"; +import axios from "axios"; +import { getConfig } from "./getConfig"; +import { getStateVariables } from "./getStateVariables"; export function buildStatusIndicators( config: ReturnType, @@ -231,7 +233,24 @@ export function buildStatusIndicators( try { indicators.push({ - statusFunc: getBlockFee, + statusFunc: async ( + provider: ethers.providers.JsonRpcProvider, + contractAddress: string + ): Promise => { + const contract: Contract = new Contract( + contractAddress, + TaikoL1, + provider + ); + const fee = await contract.getBlockFee(); + const tko: Contract = new Contract( + config.taikoTokenAddress, + TaikoToken, + provider + ); + const decimals = await tko.decimals(); + return `${ethers.utils.formatUnits(fee, decimals)} TKO`; + }, watchStatusFunc: null, provider: config.l1Provider, contractAddress: config.l1TaikoAddress, @@ -244,7 +263,30 @@ export function buildStatusIndicators( "The current fee to propose a block to the TaikoL1 smart contract.", }); indicators.push({ - statusFunc: getProofReward, + statusFunc: async ( + provider: ethers.providers.JsonRpcProvider, + contractAddress: string + ): Promise => { + const contract: Contract = new Contract( + contractAddress, + TaikoL1, + provider + ); + const averageProofTime = await getAverageProofTime( + config.eventIndexerApiUrl + ); + const fee = await contract.getProofReward(Number(averageProofTime)); + + const tko: Contract = new Contract( + config.taikoTokenAddress, + TaikoToken, + provider + ); + const decimals = await tko.decimals(); + return `${ethers.utils.formatUnits(fee, decimals)} ${ + import.meta.env.VITE_FEE_TOKEN_SYMBOL ?? "TKO" + }`; + }, watchStatusFunc: null, provider: config.l1Provider, contractAddress: config.l1TaikoAddress, @@ -254,7 +296,7 @@ export function buildStatusIndicators( return "green"; // todo: whats green, yellow, red? }, tooltip: - "The current reward for successfully submitting a proof for a proposed block on the TaikoL1 smart contract.", + "The current reward for successfully submitting a proof for a proposed block on the TaikoL1 smart contract, given the proof time is equal to average proof time.", }); indicators.push({ provider: config.l1Provider, @@ -283,7 +325,7 @@ export function buildStatusIndicators( if ( prover.toLowerCase() !== config.oracleProverAddress.toLowerCase() ) { - onEvent(new Date().getTime().toString()); + onEvent(new Date(provenAt).toTimeString()); } } ); @@ -294,6 +336,25 @@ export function buildStatusIndicators( tooltip: "The most recent block proof submitted on TaikoL1 contract.", }); + indicators.push({ + provider: config.l1Provider, + contractAddress: config.l1TaikoAddress, + statusFunc: async ( + provider: ethers.providers.JsonRpcProvider, + address: string + ) => { + const config = await getStateVariables(provider, address); + return config.proofTimeTarget.toNumber(); + }, + colorFunc: function (status: Status) { + return "green"; + }, + header: "Proof Time Target (seconds)", + intervalInMs: 5 * 1000, + tooltip: + "The proof time target the protocol intends the average proof time to be", + }); + indicators.push({ provider: config.l1Provider, contractAddress: config.l1TaikoAddress, @@ -304,7 +365,7 @@ export function buildStatusIndicators( colorFunc: function (status: Status) { return "green"; }, - header: "Average Proof Time", + header: "Average Proof Time (seconds)", intervalInMs: 5 * 1000, tooltip: "The current average proof time, updated when a block is successfully proven.", @@ -315,8 +376,22 @@ export function buildStatusIndicators( contractAddress: config.l1TaikoAddress, statusFunc: async ( provider: ethers.providers.JsonRpcProvider, - address: string - ) => await getAverageProofReward(config.eventIndexerApiUrl), + contractAdress: string + ) => { + const resp = await axios.get( + `${config.eventIndexerApiUrl}/stats` + ); + const tko: Contract = new Contract( + config.taikoTokenAddress, + TaikoToken, + provider + ); + const decimals = await tko.decimals(); + return `${ethers.utils.formatUnits( + resp.data.averageProofReward, + decimals + )} TKO`; + }, colorFunc: function (status: Status) { return "green"; }, diff --git a/packages/status-page/src/utils/getAverageProofReward.ts b/packages/status-page/src/utils/getAverageProofReward.ts index f57447a01b9..6c51612e3cd 100644 --- a/packages/status-page/src/utils/getAverageProofReward.ts +++ b/packages/status-page/src/utils/getAverageProofReward.ts @@ -1,16 +1,6 @@ -import axios from "axios"; -import { ethers } from "ethers"; - export type StatsResponse = { id: number; averageProofTime: number; averageProofReward: number; numProofs: number; }; -export const getAverageProofReward = async ( - eventIndexerApiUrl: string -): Promise => { - const resp = await axios.get(`${eventIndexerApiUrl}/stats`); - - return `${ethers.utils.formatUnits(resp.data.averageProofReward)} TKO`; -}; diff --git a/packages/status-page/src/utils/getAverageProofTime.ts b/packages/status-page/src/utils/getAverageProofTime.ts index d8a5fd2ef08..8a4b2430e0b 100644 --- a/packages/status-page/src/utils/getAverageProofTime.ts +++ b/packages/status-page/src/utils/getAverageProofTime.ts @@ -6,5 +6,5 @@ export const getAverageProofTime = async ( ): Promise => { const resp = await axios.get(`${eventIndexerApiUrl}/stats`); - return `${resp.data.averageProofTime} seconds`; + return `${resp.data.averageProofTime}`; }; diff --git a/packages/status-page/src/utils/getBlockFee.ts b/packages/status-page/src/utils/getBlockFee.ts deleted file mode 100644 index 971ad54db17..00000000000 --- a/packages/status-page/src/utils/getBlockFee.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigNumber, Contract, ethers } from "ethers"; -import TaikoL1 from "../constants/abi/TaikoL1"; - -export const getBlockFee = async ( - provider: ethers.providers.JsonRpcProvider, - contractAddress: string -): Promise => { - const contract: Contract = new Contract(contractAddress, TaikoL1, provider); - const fee = await contract.getBlockFee(); - return ethers.utils.formatEther(fee); -}; diff --git a/packages/status-page/src/utils/getProofReward.ts b/packages/status-page/src/utils/getProofReward.ts deleted file mode 100644 index a5862081f26..00000000000 --- a/packages/status-page/src/utils/getProofReward.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BigNumber, Contract, ethers } from "ethers"; -import TaikoL1 from "../constants/abi/TaikoL1"; -import { truncateString } from "./truncateString"; - -export const getProofReward = async ( - provider: ethers.providers.JsonRpcProvider, - contractAddress: string -): Promise => { - const contract: Contract = new Contract(contractAddress, TaikoL1, provider); - const fee = await contract.getProofReward(10000); - return `${truncateString(ethers.utils.formatEther(fee), 8)} ${ - import.meta.env.VITE_FEE_TOKEN_SYMBOL ?? "TKO" - }`; -}; diff --git a/packages/status-page/src/utils/initConfig.ts b/packages/status-page/src/utils/initConfig.ts index d7625fbe487..78ad843d667 100644 --- a/packages/status-page/src/utils/initConfig.ts +++ b/packages/status-page/src/utils/initConfig.ts @@ -21,6 +21,7 @@ export function initConfig(layer: Layer) { layer === Layer.Two ? import.meta.env.VITE_L2_TAIKO_L2_ADDRESS : import.meta.env.VITE_L3_TAIKO_L2_ADDRESS; + const taikoTokenAddress = import.meta.env.VITE_TAIKO_TOKEN_ADDRESS; const l1ExplorerUrl = import.meta.env.VITE_L1_EXPLORER_URL; const l2ExplorerUrl = layer === Layer.Two @@ -39,6 +40,7 @@ export function initConfig(layer: Layer) { l2Provider, l1TaikoAddress, l2TaikoAddress, + taikoTokenAddress, l1ExplorerUrl, l2ExplorerUrl, feeTokenSymbol,