Skip to content

Commit add1428

Browse files
authored
feat: allow proposing without connecting a wallet (#2262)
* feat: allow proposing without connecting a wallet * fix: remove unused imports * fix: remove connected * use useMemo * cleanup multisig context * remove undefined checks * rename squads to walletsquads
1 parent 792520d commit add1428

File tree

7 files changed

+88
-102
lines changed

7 files changed

+88
-102
lines changed

governance/xc_admin/packages/xc_admin_frontend/components/PermissionDepermissionKey.tsx

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { Program } from '@coral-xyz/anchor'
22
import { Dialog, Menu, Transition } from '@headlessui/react'
33
import { PythOracle } from '@pythnetwork/client/lib/anchor'
44
import * as Label from '@radix-ui/react-label'
5-
import { useWallet } from '@solana/wallet-adapter-react'
6-
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
75
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
86
import SquadsMesh from '@sqds/mesh'
97
import axios from 'axios'
@@ -39,12 +37,12 @@ const assetTypes = [
3937
const PermissionDepermissionKey = ({
4038
isPermission,
4139
pythProgramClient,
42-
squads,
40+
readOnlySquads,
4341
proposerServerUrl,
4442
}: {
4543
isPermission: boolean
4644
pythProgramClient?: Program<PythOracle>
47-
squads?: SquadsMesh
45+
readOnlySquads: SquadsMesh
4846
proposerServerUrl: string
4947
}) => {
5048
const [publisherKey, setPublisherKey] = useState(
@@ -56,7 +54,6 @@ const PermissionDepermissionKey = ({
5654
const [priceAccounts, setPriceAccounts] = useState<PublicKey[]>([])
5755
const { cluster } = useContext(ClusterContext)
5856
const { rawConfig, dataIsLoading, connection } = usePythContext()
59-
const { connected } = useWallet()
6057

6158
// get current input value
6259

@@ -77,9 +74,9 @@ const PermissionDepermissionKey = ({
7774
}
7875

7976
const handleSubmitButton = async () => {
80-
if (pythProgramClient && squads) {
77+
if (pythProgramClient) {
8178
const instructions: TransactionInstruction[] = []
82-
const multisigAuthority = squads.getAuthorityPDA(
79+
const multisigAuthority = readOnlySquads.getAuthorityPDA(
8380
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)],
8481
1
8582
)
@@ -265,22 +262,16 @@ const PermissionDepermissionKey = ({
265262
/>
266263
</div>
267264
<div className="mt-6">
268-
{!connected ? (
269-
<div className="flex justify-center">
270-
<WalletModalButton className="action-btn text-base" />
271-
</div>
272-
) : (
273-
<button
274-
className="action-btn text-base"
275-
onClick={handleSubmitButton}
276-
>
277-
{isSubmitButtonLoading ? (
278-
<Spinner />
279-
) : (
280-
'Submit Proposal'
281-
)}
282-
</button>
283-
)}
265+
<button
266+
className="action-btn text-base"
267+
onClick={handleSubmitButton}
268+
>
269+
{isSubmitButtonLoading ? (
270+
<Spinner />
271+
) : (
272+
'Submit Proposal'
273+
)}
274+
</button>
284275
</div>
285276
</div>
286277
</Dialog.Panel>

governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { AnchorProvider, Idl, Program } from '@coral-xyz/anchor'
22
import { AccountType, getPythProgramKeyForCluster } from '@pythnetwork/client'
33
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
4-
import { useWallet } from '@solana/wallet-adapter-react'
54
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
65
import messageBuffer from 'message_buffer/idl/message_buffer.json'
76
import { MessageBuffer } from 'message_buffer/idl/message_buffer'
@@ -46,9 +45,8 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
4645
useState(false)
4746
const { cluster } = useContext(ClusterContext)
4847
const isRemote: boolean = isRemoteCluster(cluster) // Move to multisig context
49-
const { isLoading: isMultisigLoading, squads } = useMultisigContext()
48+
const { isLoading: isMultisigLoading, readOnlySquads } = useMultisigContext()
5049
const { rawConfig, dataIsLoading, connection } = usePythContext()
51-
const { connected } = useWallet()
5250
const [pythProgramClient, setPythProgramClient] =
5351
useState<Program<PythOracle>>()
5452

@@ -289,12 +287,12 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
289287
}
290288

291289
const handleSendProposalButtonClick = async () => {
292-
if (pythProgramClient && dataChanges && !isMultisigLoading && squads) {
290+
if (pythProgramClient && dataChanges && !isMultisigLoading) {
293291
const instructions: TransactionInstruction[] = []
294292
const publisherInPriceStoreInitializationsVerified: PublicKey[] = []
295293

296294
for (const symbol of Object.keys(dataChanges)) {
297-
const multisigAuthority = squads.getAuthorityPDA(
295+
const multisigAuthority = readOnlySquads.getAuthorityPDA(
298296
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)],
299297
1
300298
)
@@ -845,23 +843,21 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
845843
<button
846844
className="action-btn text-base"
847845
onClick={handleSendProposalButtonClick}
848-
disabled={isSendProposalButtonLoading || !squads}
846+
disabled={isSendProposalButtonLoading}
849847
>
850848
{isSendProposalButtonLoading ? <Spinner /> : 'Send Proposal'}
851849
</button>
852-
{!squads && <div>Please connect your wallet</div>}
853850
</>
854851
)}
855852
</>
856853
)
857854
}
858855

859-
// create anchor wallet when connected
860856
useEffect(() => {
861-
if (connected && squads && connection) {
857+
if (connection) {
862858
const provider = new AnchorProvider(
863859
connection,
864-
squads.wallet as Wallet,
860+
readOnlySquads.wallet as Wallet,
865861
AnchorProvider.defaultOptions()
866862
)
867863
setPythProgramClient(
@@ -878,7 +874,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
878874
)
879875
}
880876
}
881-
}, [connection, connected, cluster, squads])
877+
}, [connection, cluster, readOnlySquads])
882878

883879
return (
884880
<div className="relative">
@@ -903,13 +899,13 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
903899
<PermissionDepermissionKey
904900
isPermission={true}
905901
pythProgramClient={pythProgramClient}
906-
squads={squads}
902+
readOnlySquads={readOnlySquads}
907903
proposerServerUrl={proposerServerUrl}
908904
/>
909905
<PermissionDepermissionKey
910906
isPermission={false}
911907
pythProgramClient={pythProgramClient}
912-
squads={squads}
908+
readOnlySquads={readOnlySquads}
913909
proposerServerUrl={proposerServerUrl}
914910
/>
915911
</div>

governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals/Proposal.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'
21
import { useWallet } from '@solana/wallet-adapter-react'
32
import {
43
AccountMeta,
5-
Keypair,
64
PublicKey,
75
SystemProgram,
86
TransactionInstruction,
@@ -181,10 +179,10 @@ export const Proposal = ({
181179
: contextCluster
182180

183181
const {
184-
squads,
182+
walletSquads: squads,
185183
isLoading: isMultisigLoading,
186-
connection,
187184
refreshData,
185+
readOnlySquads,
188186
} = useMultisigContext()
189187
const {
190188
priceAccountKeyToSymbolMapping,
@@ -240,11 +238,7 @@ export const Proposal = ({
240238
useEffect(() => {
241239
let isCancelled = false
242240
const fetchInstructions = async () => {
243-
if (proposal && connection) {
244-
const readOnlySquads = new SquadsMesh({
245-
connection,
246-
wallet: new NodeWallet(new Keypair()),
247-
})
241+
if (proposal) {
248242
const proposalInstructions = (
249243
await getManyProposalsInstructions(readOnlySquads, [proposal])
250244
)[0]
@@ -267,7 +261,7 @@ export const Proposal = ({
267261
return () => {
268262
isCancelled = true
269263
}
270-
}, [cluster, proposal, squads, connection])
264+
}, [cluster, proposal, readOnlySquads])
271265

272266
const handleClick = async (
273267
instructionGenerator: (

governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals/ProposalRow.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import SquadsMesh from '@sqds/mesh'
21
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
32
import { useRouter } from 'next/router'
43
import { useCallback, useContext, useEffect, useRef, useState } from 'react'
@@ -7,10 +6,8 @@ import { ClusterContext } from '../../../contexts/ClusterContext'
76
import { useMultisigContext } from '../../../contexts/MultisigContext'
87
import { StatusTag } from './StatusTag'
98
import { getInstructionsSummary, getProposalStatus } from './utils'
10-
11-
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'
129
import { useWallet } from '@solana/wallet-adapter-react'
13-
import { AccountMeta, Keypair } from '@solana/web3.js'
10+
import { AccountMeta } from '@solana/web3.js'
1411
import {
1512
MultisigParser,
1613
getManyProposalsInstructions,
@@ -28,7 +25,11 @@ export const ProposalRow = ({
2825
useState<(readonly [string, number])[]>()
2926
const status = getProposalStatus(proposal, multisig)
3027
const { cluster } = useContext(ClusterContext)
31-
const { isLoading: isMultisigLoading, connection } = useMultisigContext()
28+
const {
29+
isLoading: isMultisigLoading,
30+
connection,
31+
readOnlySquads,
32+
} = useMultisigContext()
3233
const router = useRouter()
3334
const elementRef = useRef(null)
3435
const { publicKey: walletPublicKey } = useWallet()
@@ -51,7 +52,7 @@ export const ProposalRow = ({
5152
const element = elementRef.current
5253
const observer = new IntersectionObserver(async (entries) => {
5354
if (entries[0].isIntersecting) {
54-
if (isMultisigLoading || !connection) {
55+
if (isMultisigLoading) {
5556
return
5657
}
5758

@@ -75,10 +76,6 @@ export const ProposalRow = ({
7576

7677
// calculate instructions summary
7778
if (!instructions) {
78-
const readOnlySquads = new SquadsMesh({
79-
connection,
80-
wallet: new NodeWallet(new Keypair()),
81-
})
8279
const proposalInstructions = (
8380
await getManyProposalsInstructions(readOnlySquads, [proposal])
8481
)[0]
@@ -130,7 +127,15 @@ export const ProposalRow = ({
130127
observer.unobserve(element)
131128
}
132129
}
133-
}, [time, cluster, proposal, connection, isMultisigLoading, instructions])
130+
}, [
131+
time,
132+
cluster,
133+
proposal,
134+
connection,
135+
readOnlySquads,
136+
isMultisigLoading,
137+
instructions,
138+
])
134139

135140
const handleClickIndividualProposal = useCallback(
136141
(proposalPubkey: string) => {

governance/xc_admin/packages/xc_admin_frontend/components/tabs/UpdatePermissions.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ const UpdatePermissions = () => {
110110
const [isSendProposalButtonLoading, setIsSendProposalButtonLoading] =
111111
useState(false)
112112
const { cluster } = useContext(ClusterContext)
113-
const { isLoading: isMultisigLoading, squads } = useMultisigContext()
113+
const { isLoading: isMultisigLoading, walletSquads } = useMultisigContext()
114114
const { rawConfig, dataIsLoading, connection } = usePythContext()
115115
const { connected } = useWallet()
116116
const [pythProgramClient, setPythProgramClient] =
@@ -239,12 +239,12 @@ const UpdatePermissions = () => {
239239
}
240240

241241
const handleSendProposalButtonClick = () => {
242-
if (pythProgramClient && finalPubkeyChanges && squads) {
242+
if (pythProgramClient && finalPubkeyChanges && walletSquads) {
243243
const programDataAccount = PublicKey.findProgramAddressSync(
244244
[pythProgramClient?.programId.toBuffer()],
245245
BPF_UPGRADABLE_LOADER
246246
)[0]
247-
const multisigAuthority = squads.getAuthorityPDA(
247+
const multisigAuthority = walletSquads.getAuthorityPDA(
248248
UPGRADE_MULTISIG[getMultisigCluster(cluster)],
249249
1
250250
)
@@ -267,9 +267,9 @@ const UpdatePermissions = () => {
267267
setIsSendProposalButtonLoading(true)
268268
try {
269269
const vault = new MultisigVault(
270-
squads.wallet as Wallet,
270+
walletSquads.wallet as Wallet,
271271
getMultisigCluster(cluster),
272-
squads,
272+
walletSquads,
273273
UPGRADE_MULTISIG[getMultisigCluster(cluster)]
274274
)
275275

@@ -335,17 +335,17 @@ const UpdatePermissions = () => {
335335

336336
// create anchor wallet when connected
337337
useEffect(() => {
338-
if (connected && squads && connection) {
338+
if (connected && walletSquads && connection) {
339339
const provider = new AnchorProvider(
340340
connection,
341-
squads.wallet as Wallet,
341+
walletSquads.wallet as Wallet,
342342
AnchorProvider.defaultOptions()
343343
)
344344
setPythProgramClient(
345345
pythOracleProgram(getPythProgramKeyForCluster(cluster), provider)
346346
)
347347
}
348-
}, [connection, connected, cluster, squads])
348+
}, [connection, connected, cluster, walletSquads])
349349

350350
return (
351351
<div className="relative">

governance/xc_admin/packages/xc_admin_frontend/contexts/MultisigContext.tsx

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import React, { createContext, useContext, useMemo } from 'react'
22
import { MultisigHookData, useMultisig } from '../hooks/useMultisig'
33

4-
const MultisigContext = createContext<MultisigHookData>({
5-
upgradeMultisigAccount: undefined,
6-
priceFeedMultisigAccount: undefined,
7-
upgradeMultisigProposals: [],
8-
priceFeedMultisigProposals: [],
9-
isLoading: true,
10-
squads: undefined,
11-
refreshData: undefined,
12-
connection: undefined,
13-
})
4+
const MultisigContext = createContext<MultisigHookData | undefined>(undefined)
145

15-
export const useMultisigContext = () => useContext(MultisigContext)
6+
export const useMultisigContext = () => {
7+
const context = useContext(MultisigContext)
8+
if (!context) {
9+
throw new Error(
10+
'useMultisigContext must be used within a MultisigContext.Provider'
11+
)
12+
}
13+
return context
14+
}
1615

1716
interface MultisigContextProviderProps {
1817
children?: React.ReactNode
@@ -23,13 +22,14 @@ export const MultisigContextProvider: React.FC<
2322
> = ({ children }) => {
2423
const {
2524
isLoading,
26-
squads,
25+
walletSquads,
2726
upgradeMultisigAccount,
2827
priceFeedMultisigAccount,
2928
upgradeMultisigProposals,
3029
priceFeedMultisigProposals,
3130
refreshData,
3231
connection,
32+
readOnlySquads,
3333
} = useMultisig()
3434

3535
const value = useMemo(
@@ -39,19 +39,21 @@ export const MultisigContextProvider: React.FC<
3939
upgradeMultisigProposals,
4040
priceFeedMultisigProposals,
4141
isLoading,
42-
squads,
42+
walletSquads,
4343
refreshData,
4444
connection,
45+
readOnlySquads,
4546
}),
4647
[
47-
squads,
48+
walletSquads,
4849
isLoading,
4950
upgradeMultisigAccount,
5051
priceFeedMultisigAccount,
5152
upgradeMultisigProposals,
5253
priceFeedMultisigProposals,
5354
refreshData,
5455
connection,
56+
readOnlySquads,
5557
]
5658
)
5759

0 commit comments

Comments
 (0)