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
Binary file added load-safe-todo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,6 @@
"budgetPercentIncreaseRed": 20,
"minimumChangeThreshold": 0,
"showDetails": true
}
},
"packageManager": "yarn@1.22.22"
}
51 changes: 28 additions & 23 deletions src/components/common/NetworkSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,34 @@ const NetworkSelector = (props: { onChainSelect?: () => void }): ReactElement =>
[router],
)

const handleDeleteChain = (e: React.MouseEvent, chain: ChainInfo) => {
e.preventDefault()
e.stopPropagation()

// Remove the chain from the store
dispatch(removeChain(chain.chainId))

// Show notification
dispatch(
showNotification({
message: `${chain.chainName} network has been removed`,
groupKey: 'delete-network-success',
variant: 'success',
}),
)

// If we're currently on this chain, redirect to mainnet or another chain
if (chainId === chain.chainId) {
const defaultChain = configs.find((c) => !c.custom)
if (defaultChain) {
router.push(getNetworkLink(defaultChain.shortName))
// Wrap handleDeleteChain in useCallback
const handleDeleteChain = useCallback(
(e: React.MouseEvent, chain: ChainInfo) => {
e.preventDefault()
e.stopPropagation()

// Remove the chain from the store
dispatch(removeChain(chain.chainId))

// Show notification
dispatch(
showNotification({
message: `${chain.chainName} network has been removed`,
groupKey: 'delete-network-success',
variant: 'success',
}),
)

// If we're currently on this chain, redirect to mainnet or another chain
if (chainId === chain.chainId) {
const defaultChain = configs.find((c) => !c.custom)
if (defaultChain) {
router.push(getNetworkLink(defaultChain.shortName))
}
}
}
}
},
[chainId, configs, dispatch, getNetworkLink, router],
)

const onChange = (event: SelectChangeEvent) => {
event.preventDefault() // Prevent the link click
Expand Down Expand Up @@ -156,6 +160,7 @@ const NetworkSelector = (props: { onChainSelect?: () => void }): ReactElement =>
{customChains.length > 0 && <Divider sx={{ my: 1 }} />}

{/* Production Networks */}
<ListSubheader className={css.listSubHeader}>Production Networks</ListSubheader>
{prodNets.map((chain) => renderMenuItem(chain))}

{/* Testnets */}
Expand Down
2 changes: 2 additions & 0 deletions src/components/new-safe/create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export type NewSafeFormData = {
owners: NamedAddress[]
saltNonce: number
safeAddress?: string
multisendAddress?: string
multisendCallOnlyAddress?: string
}

const staticHints: Record<
Expand Down
4 changes: 4 additions & 0 deletions src/components/new-safe/create/logic/address-book.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const updateAddressBook = (
name: string,
owners: NamedAddress[],
threshold: number,
multisendAddress?: string,
multisendCallOnlyAddress?: string,
): AppThunk => {
return (dispatch) => {
dispatch(
Expand Down Expand Up @@ -39,6 +41,8 @@ export const updateAddressBook = (
})),
chainId: chainId,
nonce: 0,
multisendAddress: multisendAddress ? { value: multisendAddress } : null,
multisendCallOnlyAddress: multisendCallOnlyAddress ? { value: multisendCallOnlyAddress } : null,
},
}),
)
Expand Down
16 changes: 14 additions & 2 deletions src/components/new-safe/create/logic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,23 @@ export const estimateSafeCreationGas = async (
})
}

export const pollSafeInfo = async (web3: Provider, chainId: string, safeAddress: string): Promise<SafeInfo> => {
export const pollSafeInfo = async (
web3: Provider,
chainId: string,
safeAddress: string,
multiSendAddress?: string,
multisendCallOnlyAddress?: string,
): Promise<SafeInfo> => {
// exponential delay between attempts for around 4 min
return backOff(
async () => {
let [sdk, implementation] = await getSafeSDKAndImplementation(web3, safeAddress, chainId)
let [sdk, implementation] = await getSafeSDKAndImplementation(
web3,
safeAddress,
chainId,
multiSendAddress,
multisendCallOnlyAddress,
)
if (!sdk) {
throw new Error('Safe SDK not available')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,25 @@ const useSafeCreationEffects = ({
// Asynchronously wait for Safe creation
useEffect(() => {
if (status === SafeCreationStatus.SUCCESS && pendingSafe?.safeAddress && web3ReadOnly) {
pollSafeInfo(web3ReadOnly, chainId, pendingSafe.safeAddress)
pollSafeInfo(
web3ReadOnly,
chainId,
pendingSafe.safeAddress,
pendingSafe.multisendAddress,
pendingSafe.multisendCallOnlyAddress,
)
.then(() => setStatus(SafeCreationStatus.INDEXED))
.catch(() => setStatus(SafeCreationStatus.INDEX_FAILED))
}
}, [chainId, pendingSafe?.safeAddress, web3ReadOnly, status, setStatus])
}, [
chainId,
pendingSafe?.safeAddress,
pendingSafe?.multisendAddress,
pendingSafe?.multisendCallOnlyAddress,
web3ReadOnly,
status,
setStatus,
])

// Warn about leaving the page before Safe creation
useEffect(() => {
Expand All @@ -54,6 +68,8 @@ const useSafeCreationEffects = ({
pendingSafe.name,
pendingSafe.owners,
pendingSafe.threshold,
pendingSafe.multisendAddress,
pendingSafe.multisendCallOnlyAddress,
),
)
}
Expand Down
10 changes: 7 additions & 3 deletions src/components/new-safe/load/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import { AppRoutes } from '@/config/routes'
import SafeOwnerStep from '@/components/new-safe/load/steps/SafeOwnerStep'
import SafeReviewStep from '@/components/new-safe/load/steps/SafeReviewStep'

export type LoadSafeFormData = NamedAddress & {
threshold: number
owners: NamedAddress[]
export type LoadSafeFormData = {
name: string
address: string
threshold?: number
owners?: NamedAddress[]
multisendAddress?: string
multisendCallOnlyAddress?: string
}

export const LoadSafeSteps: TxStepperProps<LoadSafeFormData>['steps'] = [
Expand Down
10 changes: 8 additions & 2 deletions src/components/new-safe/load/steps/SafeOwnerStep/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,19 @@ const SafeOwnerStep = ({ data, onSubmit, onBack }: StepRenderProps<LoadSafeFormD
}

if (data.address) {
let [sdk, implementation] = await getSafeSDKAndImplementation(web3ReadOnly, data.address, chainId)
let [sdk, implementation] = await getSafeSDKAndImplementation(
web3ReadOnly,
data.address,
chainId,
data.multisendAddress,
data.multisendCallOnlyAddress,
)
if (!sdk) {
throw new Error('Unable to initialize Safe SDK')
}
return await getSafeInfo(sdk, implementation)
}
}, [data.address, web3ReadOnly, chainId])
}, [data.address, data.multisendAddress, data.multisendCallOnlyAddress, web3ReadOnly, chainId])

useEffect(() => {
if (!safeInfo) return
Expand Down
14 changes: 9 additions & 5 deletions src/components/new-safe/load/steps/SafeReviewStep/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,22 @@ const SafeReviewStep = ({ data, onBack }: StepRenderProps<LoadSafeFormData>) =>
const addSafe = () => {
const safeName = data.name
const safeAddress = data.address
const multisendAddress = data.multisendAddress || null
const multisendCallOnlyAddress = data.multisendCallOnlyAddress || null

dispatch(
addOrUpdateSafe({
safe: {
...defaultSafeInfo,
address: { value: safeAddress, name: safeName },
threshold: data.threshold,
owners: data.owners.map((owner) => ({
threshold: data.threshold ?? 1,
owners: (data.owners || []).map((owner) => ({
value: owner.address,
name: owner.name || owner.ens,
})),
chainId,
multisendAddress: multisendAddress ? { value: multisendAddress } : null, // Include multisend addresses in the safe data
multisendCallOnlyAddress: multisendCallOnlyAddress ? { value: multisendCallOnlyAddress } : null,
},
}),
)
Expand All @@ -50,7 +54,7 @@ const SafeReviewStep = ({ data, onBack }: StepRenderProps<LoadSafeFormData>) =>
}),
)

for (const { address, name, ens } of data.owners) {
for (const { address, name, ens } of data.owners || []) {
const entryName = name || ens

if (!entryName) {
Expand Down Expand Up @@ -86,7 +90,7 @@ const SafeReviewStep = ({ data, onBack }: StepRenderProps<LoadSafeFormData>) =>
name="Owners"
value={
<Box className={css.ownersArray}>
{data.owners.map((owner, index) => (
{(data.owners || []).map((owner, index) => (
<EthHashInfo
address={owner.address}
name={owner.name || owner.ens}
Expand All @@ -105,7 +109,7 @@ const SafeReviewStep = ({ data, onBack }: StepRenderProps<LoadSafeFormData>) =>
name="Threshold"
value={
<Typography>
{data.threshold} out of {data.owners.length} owner(s)
{data.threshold} out of {(data.owners || []).length} owner(s)
</Typography>
}
/>
Expand Down
Loading
Loading