UNPKG

@river-build/web3

Version:

Dapps for our Space and Registry contracts

214 lines 8.79 kB
import { WalletAlreadyLinkedError, WalletNotLinkedError } from '../error-types'; import { IWalletLinkShim } from './WalletLinkShim'; import { createEip712LinkedWalletdData } from './EIP-712'; export const INVALID_ADDRESS = '0x0000000000000000000000000000000000000000'; export class WalletLink { LINKED_WALLET_MESSAGE = 'Link your external wallet'; walletLinkShim; eip712Domain; address; constructor(config, provider) { this.walletLinkShim = new IWalletLinkShim(config.addresses.spaceFactory, provider); this.address = config.addresses.spaceFactory; this.eip712Domain = { name: 'SpaceFactory', version: '1', chainId: config.chainId, verifyingContract: config.addresses.spaceFactory, }; } async isLinked(walletAddress) { const rootKeyAddress = await this.walletLinkShim.read.getRootKeyForWallet(walletAddress); return rootKeyAddress !== INVALID_ADDRESS; } async assertNotLinked(wallet) { const walletAddress = typeof wallet === 'string' ? wallet : await wallet.getAddress(); if (await this.isLinked(walletAddress)) { throw new WalletAlreadyLinkedError(); } return { walletAddress }; } async assertLinked(walletAddress) { if (!(await this.isLinked(walletAddress))) { throw new WalletNotLinkedError(); } return { walletAddress }; } generateRootKeySignatureForWallet({ rootKey, walletAddress, rootKeyNonce, }) { const { domain, types, value } = createEip712LinkedWalletdData({ domain: this.eip712Domain, message: this.LINKED_WALLET_MESSAGE, nonce: rootKeyNonce, userID: walletAddress, }); return this.signTypedData(rootKey, domain, types, value); } generateWalletSignatureForRootKey({ wallet, rootKeyAddress, nonce: rootKeyNonce, }) { const { domain, types, value } = createEip712LinkedWalletdData({ domain: this.eip712Domain, message: this.LINKED_WALLET_MESSAGE, nonce: rootKeyNonce, userID: rootKeyAddress, }); return this.signTypedData(wallet, domain, types, value); } generateRootKeySignatureForCallerData({ rootKey, walletAddress, rootKeyNonce, }) { const { domain, types, value } = createEip712LinkedWalletdData({ domain: this.eip712Domain, message: this.LINKED_WALLET_MESSAGE, nonce: rootKeyNonce, userID: walletAddress, }); return this.signTypedData(rootKey, domain, types, value); } async generateLinkCallerData(message, rootKey, wallet) { const { walletAddress } = await this.assertNotLinked(wallet); const rootKeyAddress = await rootKey.getAddress(); const nonce = await this.walletLinkShim.read.getLatestNonceForRootKey(rootKeyAddress); const rootKeySignature = await this.generateRootKeySignatureForCallerData({ rootKey, walletAddress: walletAddress, rootKeyNonce: nonce, }); const rootKeyData = { addr: rootKeyAddress, signature: rootKeySignature, message, }; return { rootKeyData, nonce }; } async generateLinkWalletData(message, rootKey, wallet) { const { walletAddress } = await this.assertNotLinked(wallet); const rootKeyAddress = await rootKey.getAddress(); const nonce = await this.walletLinkShim.read.getLatestNonceForRootKey(rootKeyAddress); // sign root key with new wallet address const rootKeySignature = await this.generateRootKeySignatureForWallet({ rootKey, walletAddress: walletAddress, rootKeyNonce: nonce, }); // sign new wallet with root key address const walletSignature = await this.generateWalletSignatureForRootKey({ wallet, rootKeyAddress: rootKeyAddress, nonce, }); const rootKeyData = { addr: rootKeyAddress, signature: rootKeySignature, message, }; const walletData = { addr: walletAddress, signature: walletSignature, message, }; return { rootKeyData, walletData, nonce }; } /** * Link a wallet to the root key with the wallet as the caller * @param rootKey * @param wallet */ async linkCallerToRootKey(rootKey, wallet) { const { rootKeyData, nonce } = await this.generateLinkCallerData(this.LINKED_WALLET_MESSAGE, rootKey, wallet); // msg.sender = new wallet return this.walletLinkShim.write(wallet).linkCallerToRootKey(rootKeyData, nonce); } /** * Link a wallet to the root key with the root key as the caller * * @param wallet * @param rootKey * @returns */ async linkWalletToRootKey(rootKey, wallet) { const { walletData, rootKeyData, nonce } = await this.generateLinkWalletData(this.LINKED_WALLET_MESSAGE, rootKey, wallet); // msg.sender = root key return this.walletLinkShim .write(rootKey) .linkWalletToRootKey(walletData, rootKeyData, nonce); } async encodeLinkCallerToRootKey(rootKey, wallet) { const { rootKeyData, nonce } = await this.generateLinkCallerData(this.LINKED_WALLET_MESSAGE, rootKey, wallet); return this.walletLinkShim.interface.encodeFunctionData('linkCallerToRootKey', [ rootKeyData, nonce, ]); } async encodeLinkWalletToRootKey(rootKey, wallet) { const { walletData, rootKeyData, nonce } = await this.generateLinkWalletData(this.LINKED_WALLET_MESSAGE, rootKey, wallet); return this.walletLinkShim.interface.encodeFunctionData('linkWalletToRootKey', [ walletData, rootKeyData, nonce, ]); } parseError(error) { return this.walletLinkShim.parseError(error); } async getLinkedWallets(rootKey) { return this.walletLinkShim.read.getWalletsByRootKey(rootKey); } async getLinkedWalletsWithDelegations(rootKey) { return this.walletLinkShim.read.getWalletsByRootKeyWithDelegations(rootKey); } getRootKeyForWallet(wallet) { return this.walletLinkShim.read.getRootKeyForWallet(wallet); } async checkIfLinked(rootKey, wallet) { const rootKeyAddress = await rootKey.getAddress(); return this.walletLinkShim.read.checkIfLinked(rootKeyAddress, wallet); } async generateRemoveLinkData(rootKey, walletAddress) { await this.assertLinked(walletAddress); const rootKeyAddress = await rootKey.getAddress(); const nonce = await this.walletLinkShim.read.getLatestNonceForRootKey(rootKeyAddress); const { domain, types, value } = createEip712LinkedWalletdData({ domain: this.eip712Domain, message: this.LINKED_WALLET_MESSAGE, nonce, userID: walletAddress, }); const rootKeySignature = await this.signTypedData(rootKey, domain, types, value); return { rootKeyAddress, rootKeySignature, nonce }; } async removeLink(rootKey, walletAddress) { const { rootKeyAddress, rootKeySignature, nonce } = await this.generateRemoveLinkData(rootKey, walletAddress); return await this.walletLinkShim.write(rootKey).removeLink(walletAddress, { addr: rootKeyAddress, signature: rootKeySignature, message: this.LINKED_WALLET_MESSAGE, }, nonce); } /** * Remove link from this caller to a root key */ async removeCallerLink(caller) { return this.walletLinkShim.write(caller).removeCallerLink(); } async encodeRemoveLink(rootKey, walletAddress) { const { rootKeyAddress, rootKeySignature, nonce } = await this.generateRemoveLinkData(rootKey, walletAddress); return this.walletLinkShim.interface.encodeFunctionData('removeLink', [ walletAddress, { addr: rootKeyAddress, signature: rootKeySignature, message: this.LINKED_WALLET_MESSAGE, }, nonce, ]); } async signTypedData(signer, domain, types, value) { if ('_signTypedData' in signer && typeof signer._signTypedData === 'function') { return (await signer._signTypedData(domain, types, value)); } else { throw new Error('wallet does not have the function to sign typed data'); } } getInterface() { return this.walletLinkShim.interface; } } //# sourceMappingURL=WalletLink.js.map