11import { BN } from '@coral-xyz/anchor'
2- import { useWallet } from '@solana/wallet-adapter-react'
32import { AccountMeta , PublicKey } from '@solana/web3.js'
43import { getIxPDA } from '@sqds/mesh'
54import { MultisigAccount , TransactionAccount } from '@sqds/mesh/lib/types'
@@ -29,6 +28,7 @@ import { useMultisigContext } from '../../contexts/MultisigContext'
2928import CopyIcon from '../../images/icons/copy.inline.svg'
3029import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
3130import ClusterSwitch from '../ClusterSwitch'
31+ import CopyPubkey from '../common/CopyPubkey'
3232import Loadbar from '../loaders/Loadbar'
3333
3434const ProposalRow = ( {
@@ -65,30 +65,27 @@ const ProposalRow = ({
6565 }
6666 >
6767 < div className = "flex justify-between p-4" >
68- < div > { proposal . publicKey . toBase58 ( ) } </ div >
69- < div
70- className = {
71- status === 'active'
72- ? 'text-[#E6DAFE]'
73- : status === 'executed'
74- ? 'text-[#1FC3D7]'
75- : status === 'cancelled'
76- ? 'text-[#FFA7A0]'
77- : status === 'rejected'
78- ? 'text-[#F86B86]'
79- : ''
80- }
81- >
82- < strong > { status } </ strong >
68+ < div >
69+ { ' ' }
70+ < span className = "mr-2 hidden sm:block" >
71+ { proposal . publicKey . toBase58 ( ) }
72+ </ span >
73+ < span className = "mr-2 sm:hidden" >
74+ { proposal . publicKey . toBase58 ( ) . slice ( 0 , 6 ) +
75+ '...' +
76+ proposal . publicKey . toBase58 ( ) . slice ( - 6 ) }
77+ </ span > { ' ' }
8378 </ div >
79+
80+ < StatusTag proposalStatus = { status } />
8481 </ div >
8582 </ div >
8683 )
8784}
8885
8986const SignerTag = ( ) => {
9087 return (
91- < div className = "flex items-center justify-center rounded-full bg-darkGray4 py-1 px-2 text-xs" >
88+ < div className = "flex items-center justify-center rounded-full bg-[#605D72] py-1 px-2 text-xs" >
9289 Signer
9390 </ div >
9491 )
@@ -102,6 +99,26 @@ const WritableTag = () => {
10299 )
103100}
104101
102+ const StatusTag = ( { proposalStatus } : { proposalStatus : string } ) => {
103+ return (
104+ < div
105+ className = { `flex items-center justify-center rounded-full ${
106+ proposalStatus === 'active'
107+ ? 'bg-[#3C3299]'
108+ : proposalStatus === 'executed'
109+ ? 'bg-[#1C1E5D]'
110+ : proposalStatus === 'cancelled'
111+ ? 'bg-[#C4428F]'
112+ : proposalStatus === 'rejected'
113+ ? 'bg-[#CF6E42]'
114+ : 'bg-pythPurple'
115+ } py-1 px-2 text-xs`}
116+ >
117+ { proposalStatus }
118+ </ div >
119+ )
120+ }
121+
105122const Proposal = ( {
106123 proposal,
107124 multisig,
@@ -114,6 +131,7 @@ const Proposal = ({
114131 > ( [ ] )
115132 const [ isProposalInstructionsLoading , setIsProposalInstructionsLoading ] =
116133 useState ( false )
134+ const [ isVerified , setIsVerified ] = useState ( false )
117135 const { cluster } = useContext ( ClusterContext )
118136 const { squads, isLoading : isMultisigLoading } = useMultisigContext ( )
119137
@@ -141,6 +159,30 @@ const Proposal = ({
141159 } )
142160 proposalIxs . push ( parsedInstruction )
143161 }
162+ setIsVerified (
163+ proposalIxs . every (
164+ ( ix ) =>
165+ ix instanceof PythMultisigInstruction ||
166+ ( ix instanceof WormholeMultisigInstruction &&
167+ ix . name === 'postMessage' &&
168+ ix . governanceAction instanceof ExecutePostedVaa &&
169+ ix . governanceAction . instructions . every ( ( remoteIx ) => {
170+ const innerMultisigParser = MultisigParser . fromCluster (
171+ getRemoteCluster ( cluster )
172+ )
173+ const parsedRemoteInstruction =
174+ innerMultisigParser . parseInstruction ( {
175+ programId : remoteIx . programId ,
176+ data : remoteIx . data as Buffer ,
177+ keys : remoteIx . keys as AccountMeta [ ] ,
178+ } )
179+ return (
180+ parsedRemoteInstruction instanceof PythMultisigInstruction
181+ )
182+ } ) &&
183+ ix . governanceAction . targetChainId === 'pythnet' )
184+ )
185+ )
144186 setProposalInstructions ( proposalIxs )
145187 setIsProposalInstructionsLoading ( false )
146188 }
@@ -200,23 +242,32 @@ const Proposal = ({
200242 ! isProposalInstructionsLoading ? (
201243 < div className = "grid grid-cols-3 gap-4" >
202244 < div className = "col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-2" >
203- < h4 className = "h4 font-semibold" > Info</ h4 >
245+ < div className = "flex justify-between" >
246+ < h4 className = "h4 font-semibold" > Info</ h4 >
247+ < div
248+ className = { `flex items-center justify-center rounded-full py-1 px-2 text-xs ${
249+ isVerified ? 'bg-[#187B51]' : 'bg-[#8D2D41]'
250+ } `}
251+ >
252+ { isVerified ? 'Verified' : 'Unverified' }
253+ </ div >
254+ </ div >
204255 < hr className = "border-gray-700" />
205256 < div className = "flex justify-between" >
206257 < div > Status</ div >
207- < div > { Object . keys ( proposal . status ) [ 0 ] } </ div >
258+ < StatusTag proposalStatus = { proposalStatus } / >
208259 </ div >
209260 < div className = "flex justify-between" >
210261 < div > Proposal</ div >
211- < div > { proposal . publicKey . toBase58 ( ) } </ div >
262+ < CopyPubkey pubkey = { proposal . publicKey . toBase58 ( ) } / >
212263 </ div >
213264 < div className = "flex justify-between" >
214265 < div > Creator</ div >
215- < div > { proposal . creator . toBase58 ( ) } </ div >
266+ < CopyPubkey pubkey = { proposal . creator . toBase58 ( ) } / >
216267 </ div >
217268 < div className = "flex justify-between" >
218269 < div > Multisig</ div >
219- < div > { proposal . ms . toBase58 ( ) } </ div >
270+ < CopyPubkey pubkey = { proposal . ms . toBase58 ( ) } / >
220271 </ div >
221272 </ div >
222273 < div className = "col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-1" >
@@ -239,7 +290,7 @@ const Proposal = ({
239290 </ div >
240291 </ div >
241292 { proposalStatus === 'active' ? (
242- < div className = "flex items-center justify-between px -8 pt-3" >
293+ < div className = "flex items-center justify-center space-x -8 pt-3" >
243294 < button
244295 className = "action-btn text-base"
245296 onClick = { handleClickApprove }
@@ -338,15 +389,19 @@ const Proposal = ({
338389 className = "flex justify-between border-t border-beige-300 py-3"
339390 >
340391 < div > { key } </ div >
341- < div className = "max-w-sm break-all" >
342- { instruction . args [ key ] instanceof PublicKey
343- ? instruction . args [ key ] . toBase58 ( )
344- : typeof instruction . args [ key ] === 'string'
345- ? instruction . args [ key ]
346- : instruction . args [ key ] instanceof Uint8Array
347- ? instruction . args [ key ] . toString ( 'hex' )
348- : JSON . stringify ( instruction . args [ key ] ) }
349- </ div >
392+ { instruction . args [ key ] instanceof PublicKey ? (
393+ < CopyPubkey
394+ pubkey = { instruction . args [ key ] . toBase58 ( ) }
395+ />
396+ ) : (
397+ < div className = "max-w-sm break-all" >
398+ { typeof instruction . args [ key ] === 'string'
399+ ? instruction . args [ key ]
400+ : instruction . args [ key ] instanceof Uint8Array
401+ ? instruction . args [ key ] . toString ( 'hex' )
402+ : JSON . stringify ( instruction . args [ key ] ) }
403+ </ div >
404+ ) }
350405 </ div >
351406 ) ) }
352407 </ div >
@@ -385,32 +440,11 @@ const Proposal = ({
385440 { instruction . accounts . named [ key ] . isWritable ? (
386441 < WritableTag />
387442 ) : null }
388- < div
389- className = "-ml-1 inline-flex cursor-pointer items-center px-1 hover:bg-dark hover:text-white active:bg-darkGray3"
390- onClick = { ( ) => {
391- copy (
392- instruction . accounts . named [
393- key
394- ] . pubkey . toBase58 ( )
395- )
396- } }
397- >
398- < span className = "mr-2 hidden xl:block" >
399- { instruction . accounts . named [
400- key
401- ] . pubkey . toBase58 ( ) }
402- </ span >
403- < span className = "mr-2 xl:hidden" >
404- { instruction . accounts . named [ key ] . pubkey
405- . toBase58 ( )
406- . slice ( 0 , 6 ) +
407- '...' +
408- instruction . accounts . named [ key ] . pubkey
409- . toBase58 ( )
410- . slice ( - 6 ) }
411- </ span > { ' ' }
412- < CopyIcon className = "shrink-0" />
413- </ div >
443+ < CopyPubkey
444+ pubkey = { instruction . accounts . named [
445+ key
446+ ] . pubkey . toBase58 ( ) }
447+ />
414448 </ div >
415449 </ div >
416450 </ >
@@ -428,11 +462,13 @@ const Proposal = ({
428462 className = "flex justify-between"
429463 >
430464 < div > Program ID</ div >
431- < div > { instruction . instruction . programId . toBase58 ( ) } </ div >
465+ < CopyPubkey
466+ pubkey = { instruction . instruction . programId . toBase58 ( ) }
467+ />
432468 </ div >
433469 < div key = { `${ index } _data` } className = "flex justify-between" >
434470 < div > Data</ div >
435- < div >
471+ < div className = "max-w-sm break-all" >
436472 { instruction . instruction . data . length > 0
437473 ? instruction . instruction . data . toString ( 'hex' )
438474 : 'No data' }
@@ -552,27 +588,31 @@ const Proposal = ({
552588 className = "flex justify-between border-t border-beige-300 py-3"
553589 >
554590 < div > { key } </ div >
555- < div className = "max-w-sm break-all" >
556- { parsedInstruction . args [
557- key
558- ] instanceof PublicKey
559- ? parsedInstruction . args [
560- key
561- ] . toBase58 ( )
562- : typeof parsedInstruction . args [
563- key
564- ] === 'string'
565- ? parsedInstruction . args [ key ]
566- : parsedInstruction . args [
567- key
568- ] instanceof Uint8Array
569- ? parsedInstruction . args [
570- key
571- ] . toString ( 'hex' )
572- : JSON . stringify (
573- parsedInstruction . args [ key ]
574- ) }
575- </ div >
591+ { parsedInstruction . args [
592+ key
593+ ] instanceof PublicKey ? (
594+ < CopyPubkey
595+ pubkey = { parsedInstruction . args [
596+ key
597+ ] . toBase58 ( ) }
598+ />
599+ ) : (
600+ < div className = "max-w-sm break-all" >
601+ { typeof parsedInstruction . args [
602+ key
603+ ] === 'string'
604+ ? parsedInstruction . args [ key ]
605+ : parsedInstruction . args [
606+ key
607+ ] instanceof Uint8Array
608+ ? parsedInstruction . args [
609+ key
610+ ] . toString ( 'hex' )
611+ : JSON . stringify (
612+ parsedInstruction . args [ key ]
613+ ) }
614+ </ div >
615+ ) }
576616 </ div >
577617 )
578618 ) }
@@ -774,7 +814,6 @@ const Proposals = () => {
774814 priceFeedMultisigProposals,
775815 isLoading : isMultisigLoading ,
776816 } = useMultisigContext ( )
777- const { connected } = useWallet ( )
778817
779818 const handleClickBackToPriceFeeds = ( ) => {
780819 delete router . query . proposal
0 commit comments