@river-build/web3
Version:
Dapps for our Space and Registry contracts
214 lines • 8.79 kB
JavaScript
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