Skip to content

Commit

Permalink
When getting stealthKeys via subgraph StealthKeyChanged event, save b…
Browse files Browse the repository at this point in the history
…lock number of event in storage as starting point of announcements scan
  • Loading branch information
jferas committed May 6, 2024
1 parent 6d831ac commit b38db26
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 13 deletions.
13 changes: 11 additions & 2 deletions frontend/src/pages/AccountReceive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,16 @@ function useScan() {
const mostRecentBlockNumber = ref<number>(0);
// Start and end blocks for advanced mode settings
const { advancedMode, startBlock, endBlock, setScanBlocks, setScanPrivateKey, scanPrivateKey, resetScanSettings } =
useSettingsStore();
const {
advancedMode,
startBlock,
endBlock,
setScanBlocks,
setScanPrivateKey,
scanPrivateKey,
resetScanSettings,
getRegisteredBlockNumber,
} = useSettingsStore();
const { signer, userAddress: userWalletAddress, isAccountSetup, provider } = useWalletStore();
const startBlockLocal = ref<number>();
const endBlockLocal = ref<number>();
Expand Down Expand Up @@ -320,6 +328,7 @@ function useScan() {
mostRecentBlockTimestamp.value = latestBlock.timestamp;
// Default scan behavior
for await (const announcementsBatch of umbra.value.fetchSomeAnnouncements(
getRegisteredBlockNumber(),
signer.value,
userWalletAddress.value,
overrides
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/store/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const settings = {
language: 'language',
sendHistorySave: 'send-history-save',
UmbraApiVersion: 'umbra-api-version',
registeredBlockNumber: 'registered-block-number',
};

// Shared state between instances
Expand All @@ -27,6 +28,7 @@ const startBlock = ref<number | undefined>(undefined); // block number to start
const endBlock = ref<number | undefined>(undefined); // block number to scan through
const scanPrivateKey = ref<string>(); // private key entered when scanning
const lastWallet = ref<string>(); // name of last wallet used
const registeredBlockNumber = ref<number | undefined>(undefined); // block number of the when the user registered
const params = new URLSearchParams(window.location.search);
const paramLocale = params.get('locale') || undefined;

Expand All @@ -41,6 +43,9 @@ export default function useSettingsStore() {
lastWallet.value = LocalStorage.getItem(settings.lastWallet)
? String(LocalStorage.getItem(settings.lastWallet))
: undefined;
registeredBlockNumber.value = LocalStorage.getItem(settings.registeredBlockNumber)
? Number(LocalStorage.getItem(settings.registeredBlockNumber))
: undefined;
});
setLanguage(
paramLocale
Expand Down Expand Up @@ -137,6 +142,15 @@ export default function useSettingsStore() {
LocalStorage.remove(settings.UmbraApiVersion);
}

function getRegisteredBlockNumber() {
return registeredBlockNumber.value;
}

function setRegisteredBlockNumber(blockNumber: number) {
registeredBlockNumber.value = blockNumber;
LocalStorage.set(settings.registeredBlockNumber, blockNumber);
}

return {
toggleDarkMode,
toggleAdvancedMode,
Expand All @@ -158,5 +172,7 @@ export default function useSettingsStore() {
getUmbraApiVersion,
setUmbraApiVersion,
clearUmbraApiVersion,
getRegisteredBlockNumber,
setRegisteredBlockNumber,
};
}
6 changes: 4 additions & 2 deletions frontend/src/store/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,11 @@ const hasSetPublicKeysLegacy = async (name: string, provider: Provider) => {

// Helper method to check if user has registered public keys in the StealthKeyRegistry
async function getRegisteredStealthKeys(account: string, provider: Provider) {
const { setRegisteredBlockNumber } = useSettingsStore();
try {
const stealthPubKeys = await utils.lookupRecipient(account, provider); // throws if no keys found
return stealthPubKeys;
const registrationInfo = await utils.lookupRecipient(account, provider); // throws if no keys found
setRegisteredBlockNumber(Number(registrationInfo.block));
return registrationInfo;
} catch (err) {
window.logger.warn(err);
return null;
Expand Down
10 changes: 8 additions & 2 deletions umbra-js/src/classes/Umbra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import {
invalidStealthAddresses,
getEthSweepGasInfo,
lookupRecipient,
getBlockNumberUserRegistered,
assertSupportedAddress,
checkSupportedAddresses,
getBlockNumberUserRegistered,
recursiveGraphFetch,
} from '../utils/utils';
import { Umbra as UmbraContract, Umbra__factory, ERC20__factory } from '../typechain';
Expand Down Expand Up @@ -419,16 +419,22 @@ export class Umbra {
/**
* @notice Fetches Umbra event logs starting from the block user registered their stealth keys in using
* a subgraph, if available, falling back to RPC if not
* @param possibleRegisteredBlockNumber Block number when user registered their stealth keys (if known)
* @param Signer Signer with provider to use for fetching the block number (if not known) from the StealthKeyRegistry contract
* @param address Address of the user for fetching the block number (if not known) from the subgraph or StealthKeyRegistry contract
* @param overrides Override the start and end block used for scanning;
* @returns A list of Announcement events supplemented with additional metadata, such as the sender, block,
* timestamp, and txhash
* @dev If the registered block number is not known, it will be fetched from the subgraph or the StealthKeyRegistry contract
*/
async *fetchSomeAnnouncements(
possibleRegisteredBlockNumber: number | undefined,
Signer: JsonRpcSigner,
address: string,
overrides: ScanOverrides = {}
): AsyncGenerator<AnnouncementDetail[]> {
const registeredBlockNumber = await getBlockNumberUserRegistered(address, Signer.provider, this.chainConfig);
const registeredBlockNumber =
possibleRegisteredBlockNumber || (await getBlockNumberUserRegistered(address, Signer.provider, this.chainConfig));
// Get start and end blocks to scan events for
const startBlock = overrides.startBlock || registeredBlockNumber || this.chainConfig.startBlock;
const endBlock = overrides.endBlock || 'latest';
Expand Down
19 changes: 12 additions & 7 deletions umbra-js/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ export async function toAddress(name: string, provider: EthersProvider) {
/**
* @notice Returns public keys from the recipientId
* @dev When providing a public key, transaction hash, or address with advanced mode, the spending and viewing
* public keys will be the same. Only keys retrieved from the StealthKeyRegistry will have different spending
* and viewing keys
* public keys will be the same. Only keys retrieved from the StealthKeyRegistry (or the subgraph) will have different spending
* and viewing keys. Additionally, the block number when the user registered will be returned.
* @param id Recipient identifier, must be an ENS name, CNS name, address, transaction hash, or public key
* @param provider ethers provider to use
* @param options Object containing lookup options:
Expand All @@ -230,15 +230,15 @@ export async function lookupRecipient(
const isPublicKey = id.length === 132 && isHexString(id);
if (supportPubKey && isPublicKey) {
assertValidPoint(id);
return { spendingPublicKey: id, viewingPublicKey: id };
return { spendingPublicKey: id, viewingPublicKey: id, block: undefined };
}

// Check if identifier is a transaction hash. If so, we recover the sender's public keys from the transaction
const isTxHash = id.length === 66 && isHexString(id);
if (supportTxHash && isTxHash) {
const publicKey = await recoverPublicKeyFromTransaction(id, provider);
assertValidPoint(publicKey);
return { spendingPublicKey: publicKey, viewingPublicKey: publicKey };
return { spendingPublicKey: publicKey, viewingPublicKey: publicKey, block: undefined };
}

// The remaining checks are dependent on the advanced mode option. The provided identifier is now either an
Expand All @@ -259,7 +259,11 @@ export async function lookupRecipient(
stealthKeyChangedEvent.viewingPubKey,
stealthKeyChangedEvent.viewingPubKeyPrefix.toString()
);
return { spendingPublicKey: spendingPublicKey, viewingPublicKey: viewingPublicKey };
return {
spendingPublicKey: spendingPublicKey,
viewingPublicKey: viewingPublicKey,
block: stealthKeyChangedEvent.block,
};
} catch (error) {
if (error instanceof Error) {
console.log('Public key subgraph fetch error: ', error.message);
Expand All @@ -268,7 +272,8 @@ export async function lookupRecipient(
}
console.log('Error using subgraph to lookup receipient stealth keys, will query registry contract');
const registry = new StealthKeyRegistry(provider);
return registry.getStealthKeys(address);
const { spendingPublicKey, viewingPublicKey } = await registry.getStealthKeys(address);
return { spendingPublicKey, viewingPublicKey, block: undefined };
}
}

Expand All @@ -277,7 +282,7 @@ export async function lookupRecipient(
if (!txHash) throw new Error('Could not get public key because the provided account has not sent any transactions');
const publicKey = await recoverPublicKeyFromTransaction(txHash, provider);
assertValidPoint(publicKey);
return { spendingPublicKey: publicKey, viewingPublicKey: publicKey };
return { spendingPublicKey: publicKey, viewingPublicKey: publicKey, block: undefined };
}

export async function getBlockNumberUserRegistered(
Expand Down

0 comments on commit b38db26

Please sign in to comment.