Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ const General = () => {
)
toast.success(`Proposal sent! 🚀 Proposal Pubkey: ${proposalPubkey}`)
setIsSendProposalButtonLoading(false)
closeModal()
} catch (e: any) {
toast.error(capitalizeFirstLetter(e.message))
setIsSendProposalButtonLoading(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
import toast from 'react-hot-toast'
import {
ExecutePostedVaa,
getMultisigCluster,
getProposals,
getRemoteCluster,
MultisigInstruction,
MultisigParser,
Expand All @@ -23,10 +25,12 @@ import {
import { ClusterContext } from '../../contexts/ClusterContext'
import { useMultisigContext } from '../../contexts/MultisigContext'
import { usePythContext } from '../../contexts/PythContext'
import { PRICE_FEED_MULTISIG } from '../../hooks/useMultisig'
import VerifiedIcon from '../../images/icons/verified.inline.svg'
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
import ClusterSwitch from '../ClusterSwitch'
import CopyPubkey from '../common/CopyPubkey'
import Spinner from '../common/Spinner'
import Loadbar from '../loaders/Loadbar'

// check if a string is a pubkey
Expand Down Expand Up @@ -170,25 +174,37 @@ const ParsedAccountPubkeyRow = ({

const Proposal = ({
proposal,
proposalIndex,
instructions,
verified,
multisig,
}: {
proposal: TransactionAccount | undefined
proposalIndex: number
instructions: MultisigInstruction[]
verified: boolean
multisig: MultisigAccount | undefined
}) => {
const [currentProposal, setCurrentProposal] = useState<TransactionAccount>()
const [isTransactionLoading, setIsTransactionLoading] = useState(false)
const [
productAccountKeyToSymbolMapping,
setProductAccountKeyToSymbolMapping,
] = useState<{ [key: string]: string }>({})
const [priceAccountKeyToSymbolMapping, setPriceAccountKeyToSymbolMapping] =
useState<{ [key: string]: string }>({})
const { cluster } = useContext(ClusterContext)
const { squads, isLoading: isMultisigLoading } = useMultisigContext()
const {
squads,
isLoading: isMultisigLoading,
setpriceFeedMultisigProposals,
} = useMultisigContext()
const { rawConfig, dataIsLoading, connection } = usePythContext()

useEffect(() => {
setCurrentProposal(proposal)
}, [proposal])

useEffect(() => {
if (!dataIsLoading) {
const productAccountMapping: { [key: string]: string } = {}
Expand All @@ -207,12 +223,36 @@ const Proposal = ({

const proposalStatus = proposal ? Object.keys(proposal.status)[0] : 'unknown'

useEffect(() => {
// update the priceFeedMultisigProposals with previous value but replace the current proposal with the updated one at the specific index
if (currentProposal) {
setpriceFeedMultisigProposals((prevProposals: TransactionAccount[]) => {
prevProposals.splice(proposalIndex, 1, currentProposal)
return [...prevProposals]
})
}
}, [currentProposal, setpriceFeedMultisigProposals, proposalIndex])

const handleClickApprove = async () => {
if (proposal && squads) {
try {
setIsTransactionLoading(true)
await squads.approveTransaction(proposal.publicKey)
const proposals = await getProposals(
squads,
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)]
)
setCurrentProposal(
proposals.find(
(proposal) =>
proposal.publicKey.toBase58() ===
currentProposal?.publicKey.toBase58()
)
)
toast.success(`Approved proposal ${proposal.publicKey.toBase58()}`)
setIsTransactionLoading(false)
} catch (e: any) {
setIsTransactionLoading(false)
toast.error(capitalizeFirstLetter(e.message))
}
}
Expand All @@ -221,9 +261,23 @@ const Proposal = ({
const handleClickReject = async () => {
if (proposal && squads) {
try {
setIsTransactionLoading(true)
await squads.rejectTransaction(proposal.publicKey)
const proposals = await getProposals(
squads,
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)]
)
setCurrentProposal(
proposals.find(
(proposal) =>
proposal.publicKey.toBase58() ===
currentProposal?.publicKey.toBase58()
)
)
toast.success(`Rejected proposal ${proposal.publicKey.toBase58()}`)
setIsTransactionLoading(false)
} catch (e: any) {
setIsTransactionLoading(false)
toast.error(capitalizeFirstLetter(e.message))
}
}
Expand All @@ -232,9 +286,23 @@ const Proposal = ({
const handleClickExecute = async () => {
if (proposal && squads) {
try {
setIsTransactionLoading(true)
await squads.executeTransaction(proposal.publicKey)
const proposals = await getProposals(
squads,
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)]
)
setCurrentProposal(
proposals.find(
(proposal) =>
proposal.publicKey.toBase58() ===
currentProposal?.publicKey.toBase58()
)
)
toast.success(`Executed proposal ${proposal.publicKey.toBase58()}`)
setIsTransactionLoading(false)
} catch (e: any) {
setIsTransactionLoading(false)
toast.error(capitalizeFirstLetter(e.message))
}
}
Expand All @@ -243,15 +311,29 @@ const Proposal = ({
const handleClickCancel = async () => {
if (proposal && squads) {
try {
setIsTransactionLoading(true)
await squads.cancelTransaction(proposal.publicKey)
const proposals = await getProposals(
squads,
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)]
)
setCurrentProposal(
proposals.find(
(proposal) =>
proposal.publicKey.toBase58() ===
currentProposal?.publicKey.toBase58()
)
)
toast.success(`Cancelled proposal ${proposal.publicKey.toBase58()}`)
setIsTransactionLoading(false)
} catch (e: any) {
setIsTransactionLoading(false)
toast.error(capitalizeFirstLetter(e.message))
}
}
}

return proposal !== undefined &&
return currentProposal !== undefined &&
multisig !== undefined &&
!isMultisigLoading ? (
<div className="grid grid-cols-3 gap-4">
Expand All @@ -267,15 +349,15 @@ const Proposal = ({
</div>
<div className="flex justify-between">
<div>Proposal</div>
<CopyPubkey pubkey={proposal.publicKey.toBase58()} />
<CopyPubkey pubkey={currentProposal.publicKey.toBase58()} />
</div>
<div className="flex justify-between">
<div>Creator</div>
<CopyPubkey pubkey={proposal.creator.toBase58()} />
<CopyPubkey pubkey={currentProposal.creator.toBase58()} />
</div>
<div className="flex justify-between">
<div>Multisig</div>
<CopyPubkey pubkey={proposal.ms.toBase58()} />
<CopyPubkey pubkey={currentProposal.ms.toBase58()} />
</div>
</div>
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4 lg:col-span-1">
Expand All @@ -284,17 +366,17 @@ const Proposal = ({
<div className="grid grid-cols-3 justify-center gap-4 text-center align-middle">
<div>
<div className="font-bold">Confirmed</div>
<div className="text-lg">{proposal.approved.length}</div>
<div className="text-lg">{currentProposal.approved.length}</div>
</div>
{proposalStatus === 'active' || proposalStatus === 'rejected' ? (
<div>
<div className="font-bold">Rejected</div>
<div className="text-lg">{proposal.rejected.length}</div>
<div className="text-lg">{currentProposal.rejected.length}</div>
</div>
) : (
<div>
<div className="font-bold">Cancelled</div>
<div className="text-lg">{proposal.cancelled.length}</div>
<div className="text-lg">{currentProposal.cancelled.length}</div>
</div>
)}
<div>
Expand All @@ -310,13 +392,13 @@ const Proposal = ({
className="action-btn text-base"
onClick={handleClickApprove}
>
Approve
{isTransactionLoading ? <Spinner /> : 'Approve'}
</button>
<button
className="sub-action-btn text-base"
onClick={handleClickReject}
>
Reject
{isTransactionLoading ? <Spinner /> : 'Reject'}
</button>
</div>
) : proposalStatus === 'executeReady' ? (
Expand All @@ -325,17 +407,59 @@ const Proposal = ({
className="action-btn text-base"
onClick={handleClickExecute}
>
Execute
{isTransactionLoading ? <Spinner /> : 'Execute'}
</button>
<button
className="sub-action-btn text-base"
onClick={handleClickCancel}
>
Cancel
{isTransactionLoading ? <Spinner /> : 'Cancel'}
</button>
</div>
) : null}
</div>
{currentProposal.approved.length > 0 ? (
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
<h4 className="h4 font-semibold">
Confirmed: {currentProposal.approved.length}
</h4>
<hr className="border-gray-700" />
{currentProposal.approved.map((pubkey, idx) => (
<div className="flex justify-between" key={pubkey.toBase58()}>
<div>Key {idx + 1}</div>
<CopyPubkey pubkey={pubkey.toBase58()} />
</div>
))}
</div>
) : null}
{currentProposal.rejected.length > 0 ? (
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
<h4 className="h4 font-semibold">
Rejected: {currentProposal.rejected.length}
</h4>
<hr className="border-gray-700" />
{currentProposal.rejected.map((pubkey, idx) => (
<div className="flex justify-between" key={pubkey.toBase58()}>
<div>Key {idx + 1}</div>
<CopyPubkey pubkey={pubkey.toBase58()} />
</div>
))}
</div>
) : null}
{currentProposal.cancelled.length > 0 ? (
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
<h4 className="h4 font-semibold">
Cancelled: {currentProposal.cancelled.length}
</h4>
<hr className="border-gray-700" />
{currentProposal.cancelled.map((pubkey, idx) => (
<div className="flex justify-between" key={pubkey.toBase58()}>
<div>Key {idx + 1}</div>
<CopyPubkey pubkey={pubkey.toBase58()} />
</div>
))}
</div>
) : null}
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
<h4 className="h4 font-semibold">
Total Instructions: {instructions.length}
Expand Down Expand Up @@ -989,6 +1113,7 @@ const Proposals = () => {
<div className="relative mt-6">
<Proposal
proposal={currentProposal}
proposalIndex={currentProposalIndex}
instructions={allProposalsIxsParsed[currentProposalIndex]}
verified={allProposalsVerifiedArr[currentProposalIndex]}
multisig={priceFeedMultisigAccount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface MultisigContextProps {
upgradeMultisigProposals: TransactionAccount[]
priceFeedMultisigProposals: TransactionAccount[]
allProposalsIxsParsed: MultisigInstruction[][]
setpriceFeedMultisigProposals: any
}

const MultisigContext = createContext<MultisigContextProps>({
Expand All @@ -27,6 +28,7 @@ const MultisigContext = createContext<MultisigContextProps>({
isLoading: true,
error: null,
squads: undefined,
setpriceFeedMultisigProposals: () => {},
})

export const useMultisigContext = () => useContext(MultisigContext)
Expand All @@ -48,6 +50,7 @@ export const MultisigContextProvider: React.FC<
upgradeMultisigProposals,
priceFeedMultisigProposals,
allProposalsIxsParsed,
setpriceFeedMultisigProposals,
} = useMultisig(anchorWallet as Wallet)

const value = useMemo(
Expand All @@ -57,6 +60,7 @@ export const MultisigContextProvider: React.FC<
upgradeMultisigProposals,
priceFeedMultisigProposals,
allProposalsIxsParsed,
setpriceFeedMultisigProposals,
isLoading,
error,
squads,
Expand All @@ -70,6 +74,7 @@ export const MultisigContextProvider: React.FC<
upgradeMultisigProposals,
priceFeedMultisigProposals,
allProposalsIxsParsed,
setpriceFeedMultisigProposals,
]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ interface MultisigHookData {
upgradeMultisigProposals: TransactionAccount[]
priceFeedMultisigProposals: TransactionAccount[]
allProposalsIxsParsed: MultisigInstruction[][]
setpriceFeedMultisigProposals: React.Dispatch<
React.SetStateAction<TransactionAccount[]>
>
}

const getSortedProposals = async (
Expand Down Expand Up @@ -229,5 +232,6 @@ export const useMultisig = (wallet: Wallet): MultisigHookData => {
upgradeMultisigProposals,
priceFeedMultisigProposals,
allProposalsIxsParsed,
setpriceFeedMultisigProposals,
}
}