Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migration updates #930

Merged
merged 11 commits into from
Oct 4, 2024
1 change: 1 addition & 0 deletions modules/contracts/abis/mainnet/voteDelegateFactoryOld.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"_chief","type":"address"},{"internalType":"address","name":"_polling","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":true,"internalType":"address","name":"voteDelegate","type":"address"}],"name":"CreateVoteDelegate","type":"event"},{"inputs":[],"name":"chief","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"create","outputs":[{"internalType":"address","name":"voteDelegate","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"isDelegate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"polling","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
1 change: 1 addition & 0 deletions modules/contracts/eth-sdk.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const config: EthSdkConfig = {
pot: '0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7',
vat: '0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B',
voteDelegateFactory: '0x093d305366218d6d09ba10448922f10814b031dd',
voteDelegateFactoryOld: '0xD897F108670903D1d6070fcf818f9db3615AF272',
voteProxyFactory: '0x6FCD258af181B3221073A96dD90D1f7AE7eEc408',
voteProxyFactoryOld: '0xa63E145309cadaa6A903a19993868Ef7E85058BE',
vow: '0xA950524441892A31ebddF91d3cEEFa04Bf454466'
Expand Down
8 changes: 4 additions & 4 deletions modules/delegates/api/fetchDelegatedTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { SupportedNetworks } from 'modules/web3/constants/networks';
import { networkNameToChainId } from 'modules/web3/helpers/chain';
import { isAboutToExpireCheck, isExpiredCheck } from 'modules/migration/helpers/expirationChecks';
import { DelegationHistoryWithExpirationDate, MKRDelegatedToResponse } from '../types';
import { getNewOwnerFromPrevious } from 'modules/migration/delegateAddressLinks';
import { getLatestOwnerFromOld } from 'modules/migration/delegateAddressLinks';
import { Query, AllDelegatesRecord } from 'modules/gql/generated/graphql';

export async function fetchDelegatedTo(
Expand Down Expand Up @@ -79,10 +79,10 @@ export async function fetchDelegatedTo(
const isExpired = delegatingTo.delegateVersion !== 2 && isExpiredCheck(expirationDate);

// If it has a new owner address, check if it has renewed the contract
const newOwnerAddress = getNewOwnerFromPrevious(delegatingToWalletAddress as string, network);
const latestOwnerAddress = getLatestOwnerFromOld(delegatingToWalletAddress as string, network);

const newRenewedContract = newOwnerAddress
? delegates.find(d => d?.delegate?.toLowerCase() === newOwnerAddress.toLowerCase())
const newRenewedContract = latestOwnerAddress
? delegates.find(d => d?.delegate?.toLowerCase() === latestOwnerAddress.toLowerCase())
: null;

acc.push({
Expand Down
70 changes: 33 additions & 37 deletions modules/delegates/api/fetchDelegates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { formatDelegationHistory } from 'modules/delegates/helpers/formatDelegat
import { CMSProposal } from 'modules/executive/types';
import { fetchLastPollVote } from 'modules/polling/api/fetchLastPollvote';
import { isAboutToExpireCheck } from 'modules/migration/helpers/expirationChecks';
import { getNewOwnerFromPrevious, getPreviousOwnerFromNew } from 'modules/migration/delegateAddressLinks';
import { getLatestOwnerFromOld, getOriginalOwnerFromNew } from 'modules/migration/delegateAddressLinks';
import { allDelegatesCacheKey } from 'modules/cache/constants/cache-keys';
import { cacheGet, cacheSet } from 'modules/cache/cache';
import { TEN_MINUTES_IN_MS } from 'modules/app/constants/time';
Expand All @@ -47,13 +47,13 @@ import { delegationMetricsQuery } from 'modules/gql/queries/delegationMetrics';

function mergeDelegateInfo({
onChainDelegate,
previousOnChainDelegate,
originalOnChainDelegate,
newOnChainDelegate,
githubDelegate
}: {
onChainDelegate: DelegateContractInformation;
githubDelegate?: DelegateRepoInformation;
previousOnChainDelegate?: DelegateContractInformation;
originalOnChainDelegate?: DelegateContractInformation;
newOnChainDelegate?: DelegateContractInformation;
}): Delegate {
// check if contract is expired to assing the status
Expand Down Expand Up @@ -93,10 +93,10 @@ function mergeDelegateInfo({
execSupported: undefined,
mkrLockedDelegate: onChainDelegate.mkrLockedDelegate,
blockTimestamp: onChainDelegate.blockTimestamp,
...(previousOnChainDelegate && {
...(originalOnChainDelegate && {
previous: {
address: previousOnChainDelegate.address,
voteDelegateAddress: previousOnChainDelegate.voteDelegateAddress
address: originalOnChainDelegate.address,
voteDelegateAddress: originalOnChainDelegate.voteDelegateAddress
}
}),
...(newOnChainDelegate && {
Expand Down Expand Up @@ -133,32 +133,30 @@ export async function fetchDelegate(
onChainDelegate.mkrLockedDelegate = delegationEvents;

// check if delegate owner has link to a previous contract
const previousOwnerAddress = getPreviousOwnerFromNew(onChainDelegate.address, currentNetwork);
const originalOwnerAddress = getOriginalOwnerFromNew(onChainDelegate.address, currentNetwork);

// fetch the previous contract if so
const previousOnChainDelegate = previousOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === previousOwnerAddress.toLowerCase())
// fetch the original contract if so
const originalOnChainDelegate = originalOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === originalOwnerAddress.toLowerCase())
: undefined;

// check if delegate owner has a link to a newer contract
const newOwnerAddress = getNewOwnerFromPrevious(onChainDelegate.address, currentNetwork);
const latestOwnerAddress = getLatestOwnerFromOld(onChainDelegate.address, currentNetwork);

// fetch the newer contract if so
const newOnChainDelegate = newOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === newOwnerAddress.toLowerCase())
const newOnChainDelegate = latestOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === latestOwnerAddress.toLowerCase())
: undefined;

// note: this will only go back one contract relationship
// TODO: create a helper to fetch the earliest contract address
// fetch github info for delegate (if they have a link to prev contract, prev contract is the info directory key)
const { data: githubDelegate } = await fetchGithubDelegate(
previousOnChainDelegate
? previousOnChainDelegate.voteDelegateAddress
originalOnChainDelegate
? originalOnChainDelegate.voteDelegateAddress
: onChainDelegate.voteDelegateAddress,
currentNetwork
);

return mergeDelegateInfo({ onChainDelegate, previousOnChainDelegate, githubDelegate, newOnChainDelegate });
return mergeDelegateInfo({ onChainDelegate, originalOnChainDelegate, githubDelegate, newOnChainDelegate });
}

// Returns the delegate info without the chain data about votes
Expand All @@ -172,34 +170,32 @@ export async function fetchDelegatesInformation(network?: SupportedNetworks): Pr
// Map all the raw delegates info and map it to Delegate structure with the github info
const mergedDelegates: Delegate[] = onChainDelegates.map(onChainDelegate => {
// check if delegate owner has link to a previous contract
const previousOwnerAddress = getPreviousOwnerFromNew(onChainDelegate.address, currentNetwork);
const originalOwnerAddress = getOriginalOwnerFromNew(onChainDelegate.address, currentNetwork);

// fetch the previous contract if so
const previousOnChainDelegate = previousOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === previousOwnerAddress.toLowerCase())
// fetch the original contract if so
const originalOnChainDelegate = originalOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === originalOwnerAddress.toLowerCase())
: undefined;

// check if delegate owner has a link to a newer contract
const newOwnerAddress = getNewOwnerFromPrevious(onChainDelegate.address, currentNetwork);
const latestOwnerAddress = getLatestOwnerFromOld(onChainDelegate.address, currentNetwork);

// fetch the newer contract if so
const newOnChainDelegate = newOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === newOwnerAddress.toLowerCase())
const newOnChainDelegate = latestOwnerAddress
? onChainDelegates.find(i => i.address.toLowerCase() === latestOwnerAddress.toLowerCase())
: undefined;

// note: this will only go back one contract relationship
// TODO: create a helper to fetch the earliest contract address
const githubDelegate = gitHubDelegates
? gitHubDelegates.find(
i =>
i.voteDelegateAddress.toLowerCase() ===
(previousOnChainDelegate ?? onChainDelegate).voteDelegateAddress.toLowerCase()
(originalOnChainDelegate ?? onChainDelegate).voteDelegateAddress.toLowerCase()
)
: undefined;

return mergeDelegateInfo({
onChainDelegate,
previousOnChainDelegate,
originalOnChainDelegate,
githubDelegate,
newOnChainDelegate
});
Expand Down Expand Up @@ -327,11 +323,11 @@ export async function fetchAndMergeDelegates(
]);

const allDelegatesWithNamesAndLinks = allDelegateAddresses.map(delegate => {
const oldOwner = getPreviousOwnerFromNew(delegate.delegate, network);
const newOwner = getNewOwnerFromPrevious(delegate.delegate, network);
const originalOwner = getOriginalOwnerFromNew(delegate.delegate, network);
const latestOwner = getLatestOwnerFromOld(delegate.delegate, network);

const oldContractAddress = allDelegateAddresses.find(del => del.delegate === oldOwner)?.voteDelegate;
const newContractAddress = allDelegateAddresses.find(del => del.delegate === newOwner)?.voteDelegate;
const oldContractAddress = allDelegateAddresses.find(del => del.delegate === originalOwner)?.voteDelegate;
const newContractAddress = allDelegateAddresses.find(del => del.delegate === latestOwner)?.voteDelegate;

const ghDelegate = githubDelegates?.find(del =>
[delegate.voteDelegate, oldContractAddress, newContractAddress].includes(
Expand All @@ -354,12 +350,12 @@ export async function fetchAndMergeDelegates(
name: ghDelegate?.name,
picture: ghDelegate?.picture,
previous:
oldOwner && oldContractAddress
? { address: oldOwner, voteDelegateAddress: oldContractAddress }
originalOwner && oldContractAddress
? { address: originalOwner, voteDelegateAddress: oldContractAddress }
: undefined,
next:
newOwner && newContractAddress
? { address: newOwner, voteDelegateAddress: newContractAddress }
latestOwner && newContractAddress
? { address: latestOwner, voteDelegateAddress: newContractAddress }
: undefined
};
});
Expand Down
12 changes: 9 additions & 3 deletions modules/delegates/hooks/useVoteDelegateAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ type VoteDelegateAddressResponse = {

// Returns the vote delegate contract address for a account
export const useVoteDelegateAddress = (account?: string): VoteDelegateAddressResponse => {
const { voteDelegateFactory } = useContracts();
const { voteDelegateFactory, voteDelegateFactoryOld } = useContracts();

const { data, error, mutate } = useSWR(account ? `${account}/vote-delegate-address` : null, async () => {
const vdAddress = await voteDelegateFactory.delegates(account as string);
return vdAddress !== ZERO_ADDRESS ? vdAddress : undefined;
const [newVdAddress, oldVdAddress] = await Promise.all([
voteDelegateFactory.delegates(account as string),
voteDelegateFactoryOld.delegates(account as string)
]);

if (newVdAddress !== ZERO_ADDRESS) return newVdAddress;
if (oldVdAddress !== ZERO_ADDRESS) return oldVdAddress;
return undefined;
});
return {
data,
Expand Down
4 changes: 2 additions & 2 deletions modules/migration/components/ConnectWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import { useLinkedDelegateInfo } from 'modules/migration/hooks/useLinkedDelegate
import { ExternalLink } from 'modules/app/components/ExternalLink';

export function ConnectWallet(): JSX.Element {
const { newOwnerAddress } = useLinkedDelegateInfo();
const { latestOwnerAddress } = useLinkedDelegateInfo();
return (
<Flex sx={{ flexDirection: 'column' }}>
<Flex sx={{ flexDirection: 'column' }}>
<Text as="h3" sx={{ fontWeight: 'semiBold' }}>
Please switch from your old delegate address to your new delegate address
</Text>
<Label sx={{ mt: 4 }}>Your new address</Label>
<Text variant="secondary">{newOwnerAddress}</Text>
<Text variant="secondary">{latestOwnerAddress}</Text>
</Flex>
<Flex sx={{ width: '100%', my: 4 }}>
<img src="/assets/switch-account-metamask.gif" />
Expand Down
4 changes: 2 additions & 2 deletions modules/migration/components/NewAddressInitial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export function NewAddressInitial({
</Text>
<Text as="p" variant="secondary" sx={{ mt: 2 }}>
Clicking ’submit address’ spawns a message you are required to sign using your current connected
wallet. DUX team will verify the message and establish a link between your old and renewed
delegate contracts.
wallet. DUX team will verify the message and establish a link between your current contract and your new v2
delegate contract.
</Text>
</Flex>
<Flex sx={{ width: '40%' }}>
Expand Down
36 changes: 34 additions & 2 deletions modules/migration/delegateAddressLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { SupportedNetworks } from 'modules/web3/constants/networks';
export const delegateAddressLinks = {
// Format: Old Address -> new address
[SupportedNetworks.TENDERLY]: {
// Nothing
'0x14341f81dF14cA86E1420eC9e6Abd343Fb1c5bfC': '0x8e73B1922B336202E83eB458db8f60A905742193'
},
[SupportedNetworks.MAINNET]: {
// schuppi
Expand Down Expand Up @@ -59,7 +59,7 @@ export const delegateAddressLinks = {
// Sovereign Finance AVC - Cloaky
'0x86F8A04FbAF5c8eD0465624c355c1E3C073213cA': '0xe676e1Aa2419b22699aCCFc12C11761F009dDAF0',
// BLUE
'0xE5a7023f78c3c0b7B098e8f4aCE7031B3D9aFBaB': '0xe9e3951535053AF603cbE53b0753361459b74D76'
'0xE5a7023f78c3c0b7B098e8f4aCE7031B3D9aFBaB': '0xe9e3951535053AF603cbE53b0753361459b74D76',
}
};

Expand All @@ -76,6 +76,22 @@ export const getPreviousOwnerFromNew = (address: string, network: SupportedNetwo
return newToPrevMap[address.toLowerCase()];
};

export const getOriginalOwnerFromNew = (address: string, network: SupportedNetworks): string | undefined => {
let currentAddress = address.toLowerCase();
let previousAddress = getPreviousOwnerFromNew(currentAddress, network);

if (!previousAddress) {
return undefined; // No previous address found
}

while (previousAddress) {
currentAddress = previousAddress;
previousAddress = getPreviousOwnerFromNew(currentAddress, network);
}

return currentAddress;
};

export const getNewOwnerFromPrevious = (address: string, network: SupportedNetworks): string | undefined => {
const networkData = delegateAddressLinks[network] || {};

Expand All @@ -88,3 +104,19 @@ export const getNewOwnerFromPrevious = (address: string, network: SupportedNetwo

return prevToNewMap[address.toLowerCase()];
};

export const getLatestOwnerFromOld = (address: string, network: SupportedNetworks): string | undefined => {
let currentAddress = address.toLowerCase();
let newAddress = getNewOwnerFromPrevious(currentAddress, network);

if (!newAddress) {
return undefined; // No new address found
}

while (newAddress) {
currentAddress = newAddress;
newAddress = getNewOwnerFromPrevious(currentAddress, network);
}

return currentAddress;
};
40 changes: 20 additions & 20 deletions modules/migration/hooks/useLinkedDelegateInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ SPDX-License-Identifier: AGPL-3.0-or-later

import { useWeb3 } from 'modules/web3/hooks/useWeb3';
import { useDelegateContractExpirationDate } from 'modules/delegates/hooks/useDelegateContractExpirationDate';
import { getNewOwnerFromPrevious, getPreviousOwnerFromNew } from 'modules/migration/delegateAddressLinks';
import { getLatestOwnerFromOld, getOriginalOwnerFromNew } from 'modules/migration/delegateAddressLinks';

export function useLinkedDelegateInfo(): {
newOwnerAddress?: string;
newOwnerConnected: boolean;
previousOwnerAddress?: string;
previousOwnerConnected: boolean;
newOwnerHasDelegateContract: boolean;
latestOwnerAddress?: string;
latestOwnerConnected: boolean;
originalOwnerAddress?: string;
originalOwnerConnected: boolean;
latestOwnerHasDelegateContract: boolean;
} {
const { account: address, network } = useWeb3();

Expand All @@ -24,7 +24,7 @@ export function useLinkedDelegateInfo(): {
} = useDelegateContractExpirationDate();

// Means the old delegate in a mapping is connected
const previousOwnerConnected = address ? !!getNewOwnerFromPrevious(address, network) : false;
const originalOwnerConnected = address ? !!getLatestOwnerFromOld(address, network) : false;

// Means the new delegate in a mapping is connected (we need to check also that the previous owner is not connected, since an address can be, after one year, both the previous and new delegates)
/* For example:
Expand All @@ -34,30 +34,30 @@ export function useLinkedDelegateInfo(): {
}
0x2 is both a new delegate for 0x1 and a previous delegate for 0x3
*/
const newOwnerConnected = address
? !!getPreviousOwnerFromNew(address, network) && !previousOwnerConnected
const latestOwnerConnected = address
? !!getOriginalOwnerFromNew(address, network) && !originalOwnerConnected
: false;

const previousOwnerAddress = previousOwnerConnected
const originalOwnerAddress = originalOwnerConnected
? address
: address
? getPreviousOwnerFromNew(address, network)
? getOriginalOwnerFromNew(address, network)
: undefined;

const newOwnerAddress =
newOwnerConnected && !previousOwnerConnected
const latestOwnerAddress =
latestOwnerConnected && !originalOwnerConnected
? address
: address
? getNewOwnerFromPrevious(address, network)
? getLatestOwnerFromOld(address, network)
: undefined;

const newOwnerHasDelegateContract = !!delegateContractExpirationDate;
const latestOwnerHasDelegateContract = !!delegateContractExpirationDate;

return {
newOwnerAddress,
newOwnerConnected,
previousOwnerAddress,
previousOwnerConnected,
newOwnerHasDelegateContract
latestOwnerAddress,
latestOwnerConnected,
originalOwnerAddress,
originalOwnerConnected,
latestOwnerHasDelegateContract
};
}
6 changes: 3 additions & 3 deletions modules/migration/hooks/useMigrationStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export function useMigrationStatus(): {
const isShadowDelegate = voteDelegateContractAddress
? addressDetailData
? addressDetailData.delegateInfo?.name === 'Shadow Delegate'
: false
: false;
: true
: true;

const isDelegateV1Contract = !!delegateContractExpirationDate; // TODO: update with version === '1' when available
const isDelegateV1Contract = !!delegateContractExpirationDate;

const isDelegateContractExpiring =
isDelegateV1Contract && delegateContractExpirationDate
Expand Down
Loading
Loading