Up to date with main branch

This commit is contained in:
donosonaumczuk
2022-03-07 15:35:29 -03:00
17 changed files with 646 additions and 47 deletions

1
.dockerignore Normal file
View File

@@ -0,0 +1 @@
node_modules/

9
.env.example Normal file
View File

@@ -0,0 +1,9 @@
MNEMONIC=
ETHERSCAN_KEY=
INFURA_KEY=
ETHERSCAN_NETWORK=
TENDERLY_PROJECT=
TENDERLY_USERNAME=
ALCHEMY_KEY=
TENDERLY_FORK_ID=
TENDERLY_HEAD_ID=

25
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: ci
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: true
on:
push:
branches: [main]
pull_request:
jobs:
compile_and_run_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Compile code
run: npm run compile
- name: Run tests
run: npm run test

View File

@@ -1,5 +1,21 @@
# syntax=docker/dockerfile:1.3
FROM ethereum/solc:0.8.7 as build-deps
FROM node:16 as build-packages
COPY package*.json ./
COPY tsconfig*.json ./
RUN npm ci --quiet
FROM node:16
WORKDIR /src
COPY --from=build-deps /usr/bin/solc /usr/bin/solc
COPY --from=build-packages /node_modules /node_modules
COPY docker-entrypoint.sh /docker-entrypoint.sh
USER node
COPY --from=build-deps /usr/bin/solc /usr/bin/solc
ENTRYPOINT ["sh", "/docker-entrypoint.sh"]

View File

@@ -51,13 +51,13 @@ ETHERSCAN_KEY="YOUR ETHERSCAN API KEY HERE"
With the environment file set up, you can move on to using Docker:
```
$ sudo docker-compose up
$ sudo docker-compose up -d --build
```
And in another terminal:
```
$ sudo docker-compose exec contracts-env bash
$ sudo docker-compose exec contracts-env /bin/bash
```
From there, have fun!
@@ -149,7 +149,7 @@ This is a publication type that points back to another publication, whether it b
This is a publication type that points to another publication, note that mirrors cannot, themselves, be mirrored (doing so instead mirrors the pointed content). Mirrors have no original content of its own. Akin to a "share" on traditional social media. Mirrors contain:
1. An empty URI, since they cannot have content associated with them.
2. An initialized pointer, contianing the profile ID and the publication ID of the mirrored publication.
2. An initialized pointer, containing the profile ID and the publication ID of the mirrored publication.
### Profile Interaction

View File

@@ -157,6 +157,43 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
);
}
/// @inheritdoc ILensHub
function setDefaultProfile(uint256 profileId, address wallet) external override whenNotPaused {
_validateCallerIsProfileOwnerOrDispatcher(profileId);
_setDefaultProfile(profileId, wallet);
}
/// @inheritdoc ILensHub
function setDefaultProfileWithSig(DataTypes.SetDefaultProfileWithSigData calldata vars)
external
override
whenNotPaused
{
address owner = ownerOf(vars.profileId);
bytes32 digest;
unchecked {
digest = keccak256(
abi.encodePacked(
'\x19\x01',
_calculateDomainSeparator(),
keccak256(
abi.encode(
SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH,
vars.profileId,
vars.wallet,
sigNonces[owner]++,
vars.sig.deadline
)
)
)
);
}
_validateRecoveredAddress(digest, owner, vars.sig);
_setDefaultProfile(vars.profileId, vars.wallet);
}
/// @inheritdoc ILensHub
function setFollowModule(
uint256 profileId,
@@ -674,6 +711,11 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
return _profileCreatorWhitelisted[profileCreator];
}
/// @inheritdoc ILensHub
function defaultProfile(address wallet) external view override returns (uint256) {
return _defaultProfileByAddress[wallet];
}
/// @inheritdoc ILensHub
function isFollowModuleWhitelisted(address followModule) external view override returns (bool) {
return _followModuleWhitelisted[followModule];
@@ -882,6 +924,23 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
);
}
function _setDefaultProfile(uint256 profileId, address wallet) internal {
// you should only be able to map this to the owner OR dead address
if (wallet != address(0)) {
_validateWalletIsProfileOwner(profileId, wallet);
_defaultProfileByAddress[wallet] = profileId;
_addressByDefaultProfile[profileId] = wallet;
emit Events.DefaultProfileSet(profileId, wallet, block.timestamp);
} else {
// unset the default
_defaultProfileByAddress[ownerOf(profileId)] = 0;
_addressByDefaultProfile[profileId] = wallet;
emit Events.DefaultProfileSet(0, wallet, block.timestamp);
}
}
function _createComment(DataTypes.CommentData memory vars) internal {
PublishingLogic.createComment(
vars,
@@ -941,6 +1000,12 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
if (_dispatcherByProfile[tokenId] != address(0)) {
_setDispatcher(tokenId, address(0));
}
if (from != address(0)) {
_addressByDefaultProfile[tokenId] = address(0);
_defaultProfileByAddress[from] = 0;
}
super._beforeTokenTransfer(from, to, tokenId);
}
@@ -953,6 +1018,10 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
if (msg.sender != ownerOf(profileId)) revert Errors.NotProfileOwner();
}
function _validateWalletIsProfileOwner(uint256 profileId, address wallet) internal view {
if (wallet != ownerOf(profileId)) revert Errors.NotProfileOwner();
}
function _validateCallerIsGovernance() internal view {
if (msg.sender != _governance) revert Errors.NotGovernance();
}

View File

@@ -10,6 +10,11 @@ contract LensHubStorage {
// keccak256(
// 'CreateProfileWithSig(string handle,string uri,address followModule,bytes followModuleData,uint256 nonce,uint256 deadline)'
// );
bytes32 internal constant SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH =
0xae4d0f1a57c80ed196993d814b14f19b25a688b09b9cb0467c33d76e022c216f;
// keccak256(
// 'SetDefaultProfileWithSig(uint256 profileId,address wallet,uint256 nonce,uint256 deadline)'
// );
bytes32 internal constant SET_FOLLOW_MODULE_WITH_SIG_TYPEHASH =
0x6f3f6455a608af1cc57ef3e5c0a49deeb88bba264ec8865b798ff07358859d4b;
// keccak256(
@@ -66,6 +71,9 @@ contract LensHubStorage {
mapping(uint256 => DataTypes.ProfileStruct) internal _profileById;
mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct)) internal _pubByIdByProfile;
mapping(uint256 => address) internal _addressByDefaultProfile;
mapping(address => uint256) internal _defaultProfileByAddress;
uint256 internal _profileCounter;
address internal _governance;
address internal _emergencyAdmin;

View File

@@ -46,9 +46,9 @@ interface ILensHub {
* @notice Sets the protocol state to either a global pause, a publishing pause or an unpaused state. This function
* can only be called by the governance address or the emergency admin address.
*
* @param state The state to set, as a member of the ProtocolState enum.
* @param newState The state to set, as a member of the ProtocolState enum.
*/
function setState(DataTypes.ProtocolState state) external;
function setState(DataTypes.ProtocolState newState) external;
/**
* @notice Adds or removes a profile creator from the whitelist. This function can only be called by the current
@@ -99,6 +99,22 @@ interface ILensHub {
*/
function createProfile(DataTypes.CreateProfileData calldata vars) external;
/**
* @notice Sets the mapping between wallet and its main profile identity
*
* @param profileId The token ID of the profile to set as the main profile identity
* @param wallet The address of the wallet which is either the owner of the profile or address(0)
*/
function setDefaultProfile(uint256 profileId, address wallet) external;
/**
* @notice Sets the mapping between wallet and its main profile identity via signature with the specified parameters.
*
* @param vars A SetDefaultProfileWithSigData struct, including the regular parameters and an EIP712Signature struct.
*/
function setDefaultProfileWithSig(DataTypes.SetDefaultProfileWithSigData calldata vars)
external;
/**
* @notice Sets a profile's follow module, must be called by the profile owner.
*
@@ -294,6 +310,15 @@ interface ILensHub {
*/
function isProfileCreatorWhitelisted(address profileCreator) external view returns (bool);
/**
* @notice Returns default profile for a given wallet address
*
* @param wallet The address to find the default mapping
*
* @return A uint256 profile id will be 0 if not mapped
*/
function defaultProfile(address wallet) external view returns (uint256);
/**
* @notice Returns whether or not a follow module is whitelisted.
*

View File

@@ -109,6 +109,20 @@ library DataTypes {
string followNFTURI;
}
/**
* @notice A struct containing the parameters required for the `setDefaultProfileWithSig()` function. Parameters are
* the same as the regular `setDefaultProfile()` function, with an added EIP712Signature.
*
* @param profileId The token ID of the profile which will be set as default
* @param wallet The address of the wallet which is either the owner of the profile or address(0)
* @param sig The EIP712Signature struct containing the profile owner's signature.
*/
struct SetDefaultProfileWithSigData {
uint256 profileId;
address wallet;
EIP712Signature sig;
}
/**
* @notice A struct containing the parameters required for the `setFollowModuleWithSig()` function. Parameters are
* the same as the regular `setFollowModule()` function, with an added EIP712Signature.

View File

@@ -138,6 +138,15 @@ library Events {
uint256 timestamp
);
/**
* @dev Emitted when a a default profile is set for a wallet as its main identity
*
* @param profileId The token ID of the profile for which the default profile is being set.
* @param wallet The wallet which owns this profile
* @param timestamp The current block timestamp.
*/
event DefaultProfileSet(uint256 indexed profileId, address indexed wallet, uint256 timestamp);
/**
* @dev Emitted when a dispatcher is set for a specific profile.
*

View File

@@ -29,16 +29,30 @@ contract UIDataProvider {
HUB = hub;
}
/**
* @notice Returns the profile struct and latest publication struct associated with the passed
* profile ID.
*
* @param profileId The profile ID to query.
*
*
* @return A custom `LatestData` struct containing the `ProfileStruct` and the `PublicationStruct` queried.
*/
function getLatestData(uint256 profileId) external view returns (LatestData memory) {
function getLatestDataByProfile(uint256 profileId) external view returns (LatestData memory) {
DataTypes.ProfileStruct memory profileStruct = HUB.getProfile(profileId);
uint256 pubCount = profileStruct.pubCount;
return LatestData(profileStruct, HUB.getPub(profileId, pubCount));
}
/**
* @notice Returns the profile struct and latest publication struct associated with the passed
* profile ID.
*
* @param handle The handle to query.
*
* @return A custom `LatestData` struct containing the `ProfileStruct` and the `PublicationStruct` queried.
*/
function getLatestDataByHandle(string memory handle) external view returns (LatestData memory) {
uint256 profileId = HUB.getProfileIdByHandle(handle);
DataTypes.ProfileStruct memory profileStruct = HUB.getProfile(profileId);
uint256 pubCount = profileStruct.pubCount;
return LatestData(profileStruct, HUB.getPub(profileId, pubCount));

View File

@@ -2,22 +2,25 @@ version: '3.5'
services:
contracts-env:
security_opt:
- no-new-privileges
user: 1001:1001
env_file:
- .env
build:
context: ./
working_dir: /src
command: npm run run-env
stdin_open: true
tty: true
volumes:
- ./:/src
- $HOME/.tenderly/config.yaml:/root/.tenderly/config.yaml
environment:
MNEMONIC: ${MNEMONIC}
ETHERSCAN_KEY: ${ETHERSCAN_KEY}
INFURA_KEY: ${INFURA_KEY}
ETHERSCAN_NETWORK: ${ETHERSCAN_NETWORK}
TENDERLY_PROJECT: ${TENDERLY_PROJECT}
TENDERLY_USERNAME: ${TENDERLY_USERNAME}
ALCHEMY_KEY: ${ALCHEMY_KEY}
TENDERLY_FORK_ID: ${TENDERLY_FORK_ID}
TENDERLY_HEAD_ID: ${TENDERLY_HEAD_ID}
- ./:/src:rw
- $HOME/.tenderly/config.yaml:/root/.tenderly/config.yaml:ro
#environment:
#- MNEMONIC=
#- ETHERSCAN_KEY=
#- INFURA_KEY=
#- ETHERSCAN_NETWORK=
#- TENDERLY_PROJECT=
#- TENDERLY_USERNAME=
#- ALCHEMY_KEY=
#- TENDERLY_FORK_ID=
#- TENDERLY_HEAD_ID=

3
docker-entrypoint.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
[ ! -d "/src/node_modules" ] && mv /node_modules /src/node_modules ; bash

View File

@@ -1,13 +1,12 @@
import '@nomiclabs/hardhat-ethers';
import { BigNumberish, Bytes, logger, utils, BigNumber, Contract } from 'ethers';
import { TransactionReceipt } from '@ethersproject/providers';
import { hexlify, keccak256, RLP, toUtf8Bytes } from 'ethers/lib/utils';
import { TransactionResponse } from '@ethersproject/providers';
import hre, { ethers } from 'hardhat';
import { LensHub__factory } from '../../typechain-types';
import { lensHub, LENS_HUB_NFT_NAME, helper, testWallet, eventsLib } from '../__setup.spec';
import { HARDHAT_CHAINID, MAX_UINT256 } from './constants';
import { eventsLib, helper, lensHub, LENS_HUB_NFT_NAME, testWallet } from '../__setup.spec';
import { expect } from 'chai';
import { HARDHAT_CHAINID, MAX_UINT256 } from './constants';
import { hexlify, keccak256, RLP, toUtf8Bytes } from 'ethers/lib/utils';
import { LensHub__factory } from '../../typechain-types';
import { TransactionReceipt, TransactionResponse } from '@ethersproject/providers';
import hre, { ethers } from 'hardhat';
export enum ProtocolState {
Unpaused,
@@ -318,6 +317,16 @@ export async function getSetProfileImageURIWithSigParts(
return await getSig(msgParams);
}
export async function getSetDefaultProfileWithSigParts(
profileId: BigNumberish,
wallet: string,
nonce: number,
deadline: string
): Promise<{ v: number; r: string; s: string }> {
const msgParams = buildSetDefaultProfileWithSigParams(profileId, wallet, nonce, deadline);
return await getSig(msgParams);
}
export async function getSetFollowNFTURIWithSigParts(
profileId: BigNumberish,
followNFTURI: string,
@@ -595,6 +604,29 @@ const buildSetProfileImageURIWithSigParams = (
},
});
const buildSetDefaultProfileWithSigParams = (
profileId: BigNumberish,
wallet: string,
nonce: number,
deadline: string
) => ({
types: {
SetDefaultProfileWithSig: [
{ name: 'profileId', type: 'uint256' },
{ name: 'wallet', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
domain: domain(),
value: {
profileId: profileId,
wallet: wallet,
nonce: nonce,
deadline: deadline,
},
});
const buildSetFollowNFTURIWithSigParams = (
profileId: BigNumberish,
followNFTURI: string,

View File

@@ -119,7 +119,7 @@ makeSuiteCleanRoom('Following', function () {
lensHub.followWithSig({
follower: testWallet.address,
profileIds: [FIRST_PROFILE_ID],
datas: [],
datas: [[]],
sig: {
v,
r,

View File

@@ -0,0 +1,352 @@
import '@nomiclabs/hardhat-ethers';
import { expect } from 'chai';
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
import { ERRORS } from '../../helpers/errors';
import { cancelWithPermitForAll, getSetDefaultProfileWithSigParts } from '../../helpers/utils';
import {
FIRST_PROFILE_ID,
lensHub,
makeSuiteCleanRoom,
MOCK_FOLLOW_NFT_URI,
MOCK_PROFILE_HANDLE,
MOCK_PROFILE_URI,
testWallet,
userAddress,
userTwo,
userTwoAddress,
} from '../../__setup.spec';
makeSuiteCleanRoom('Default profile Functionality', function () {
context('Generic', function () {
beforeEach(async function () {
await expect(
lensHub.createProfile({
to: userAddress,
handle: MOCK_PROFILE_HANDLE,
imageURI: MOCK_PROFILE_URI,
followModule: ZERO_ADDRESS,
followModuleData: [],
followNFTURI: MOCK_FOLLOW_NFT_URI,
})
).to.not.be.reverted;
});
context('Negatives', function () {
it('UserTwo should fail to set the default profile on profile owned by user 1', async function () {
await expect(
lensHub.connect(userTwo).setDefaultProfile(FIRST_PROFILE_ID, userTwoAddress)
).to.be.revertedWith(ERRORS.NOT_PROFILE_OWNER_OR_DISPATCHER);
});
it('UserOne should fail to change the default profile for address that doesnt own the profile', async function () {
await expect(
lensHub.setDefaultProfile(FIRST_PROFILE_ID, userTwoAddress)
).to.be.revertedWith(ERRORS.NOT_PROFILE_OWNER);
});
});
context('Scenarios', function () {
it('User should set the default profile', async function () {
await expect(lensHub.setDefaultProfile(FIRST_PROFILE_ID, userAddress)).to.not.be.reverted;
expect((await lensHub.defaultProfile(userAddress)).toNumber()).to.eq(FIRST_PROFILE_ID);
});
it('User should set the default profile and then be able to unset it', async function () {
await expect(lensHub.setDefaultProfile(FIRST_PROFILE_ID, userAddress)).to.not.be.reverted;
expect((await lensHub.defaultProfile(userAddress)).toNumber()).to.eq(FIRST_PROFILE_ID);
await expect(lensHub.setDefaultProfile(FIRST_PROFILE_ID, ZERO_ADDRESS)).to.not.be.reverted;
expect((await lensHub.defaultProfile(userAddress)).toNumber()).to.eq(0);
});
it('User should set the default profile and then be able to change it to another', async function () {
await expect(lensHub.setDefaultProfile(FIRST_PROFILE_ID, userAddress)).to.not.be.reverted;
expect((await lensHub.defaultProfile(userAddress)).toNumber()).to.eq(FIRST_PROFILE_ID);
await expect(
lensHub.createProfile({
to: userAddress,
handle: new Date().getTime().toString(),
imageURI: MOCK_PROFILE_URI,
followModule: ZERO_ADDRESS,
followModuleData: [],
followNFTURI: MOCK_FOLLOW_NFT_URI,
})
).to.not.be.reverted;
await expect(lensHub.setDefaultProfile(2, userAddress)).to.not.be.reverted;
expect((await lensHub.defaultProfile(userAddress)).toNumber()).to.eq(2);
});
});
});
context('Meta-tx', function () {
beforeEach(async function () {
await expect(
lensHub.connect(testWallet).createProfile({
to: testWallet.address,
handle: MOCK_PROFILE_HANDLE,
imageURI: MOCK_PROFILE_URI,
followModule: ZERO_ADDRESS,
followModuleData: [],
followNFTURI: MOCK_FOLLOW_NFT_URI,
})
).to.not.be.reverted;
});
context('Negatives', function () {
it('TestWallet should fail to set default profile with sig with signature deadline mismatch', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
'0'
);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.be.revertedWith(ERRORS.SIGNATURE_INVALID);
});
it('TestWallet should fail to set default profile with sig with invalid deadline', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
'0'
);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: '0',
},
})
).to.be.revertedWith(ERRORS.SIGNATURE_EXPIRED);
});
it('TestWallet should fail to set default profile with sig with invalid nonce', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce + 1,
MAX_UINT256
);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.be.revertedWith(ERRORS.SIGNATURE_INVALID);
});
it('TestWallet should sign attempt to set default profile with sig, cancel with empty permitForAll, then fail to set default profile with sig', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
MAX_UINT256
);
await cancelWithPermitForAll();
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.be.revertedWith(ERRORS.SIGNATURE_INVALID);
});
});
context('Scenarios', function () {
it('TestWallet should set the default profile with sig', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
MAX_UINT256
);
const defaultProfileBeforeUse = await lensHub.defaultProfile(testWallet.address);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.not.be.reverted;
const defaultProfileAfter = await lensHub.defaultProfile(testWallet.address);
expect(defaultProfileBeforeUse.toNumber()).to.eq(0);
expect(defaultProfileAfter.toNumber()).to.eq(FIRST_PROFILE_ID);
});
it('TestWallet should set the default profile with sig and then be able to unset it', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
MAX_UINT256
);
const defaultProfileBeforeUse = await lensHub.defaultProfile(testWallet.address);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.not.be.reverted;
const defaultProfileAfter = await lensHub.defaultProfile(testWallet.address);
expect(defaultProfileBeforeUse.toNumber()).to.eq(0);
expect(defaultProfileAfter.toNumber()).to.eq(FIRST_PROFILE_ID);
const nonce2 = (await lensHub.sigNonces(testWallet.address)).toNumber();
const signature2 = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
ZERO_ADDRESS,
nonce2,
MAX_UINT256
);
const defaultProfileBeforeUse2 = await lensHub.defaultProfile(testWallet.address);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: ZERO_ADDRESS,
sig: {
v: signature2.v,
r: signature2.r,
s: signature2.s,
deadline: MAX_UINT256,
},
})
).to.not.be.reverted;
const defaultProfileAfter2 = await lensHub.defaultProfile(testWallet.address);
expect(defaultProfileBeforeUse2.toNumber()).to.eq(1);
expect(defaultProfileAfter2.toNumber()).to.eq(0);
});
it('TestWallet should set the default profile and then be able to change it to another', async function () {
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
const { v, r, s } = await getSetDefaultProfileWithSigParts(
FIRST_PROFILE_ID,
testWallet.address,
nonce,
MAX_UINT256
);
const defaultProfileBeforeUse = await lensHub.defaultProfile(testWallet.address);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: FIRST_PROFILE_ID,
wallet: testWallet.address,
sig: {
v,
r,
s,
deadline: MAX_UINT256,
},
})
).to.not.be.reverted;
const defaultProfileAfter = await lensHub.defaultProfile(testWallet.address);
expect(defaultProfileBeforeUse.toNumber()).to.eq(0);
expect(defaultProfileAfter.toNumber()).to.eq(FIRST_PROFILE_ID);
await expect(
lensHub.createProfile({
to: testWallet.address,
handle: new Date().getTime().toString(),
imageURI: MOCK_PROFILE_URI,
followModule: ZERO_ADDRESS,
followModuleData: [],
followNFTURI: MOCK_FOLLOW_NFT_URI,
})
).to.not.be.reverted;
const nonce2 = (await lensHub.sigNonces(testWallet.address)).toNumber();
const signature2 = await getSetDefaultProfileWithSigParts(
2,
testWallet.address,
nonce2,
MAX_UINT256
);
const defaultProfileBeforeUse2 = await lensHub.defaultProfile(testWallet.address);
await expect(
lensHub.setDefaultProfileWithSig({
profileId: 2,
wallet: testWallet.address,
sig: {
v: signature2.v,
r: signature2.r,
s: signature2.s,
deadline: MAX_UINT256,
},
})
).to.not.be.reverted;
const defaultProfileAfter2 = await lensHub.defaultProfile(testWallet.address);
expect(defaultProfileBeforeUse2.toNumber()).to.eq(1);
expect(defaultProfileAfter2.toNumber()).to.eq(2);
});
});
});
});

View File

@@ -703,24 +703,43 @@ makeSuiteCleanRoom('Misc', function () {
// Then, deploy the data provider
const dataProvider = await new UIDataProvider__factory(deployer).deploy(lensHub.address);
// Lastly, validate the result from the data provider
const result = await dataProvider.getLatestData(FIRST_PROFILE_ID);
const pubStruct = result.publicationStruct;
const profileStruct = result.profileStruct;
// `getLatestDataByProfile`, validate the result from the data provider
const resultByProfileId = await dataProvider.getLatestDataByProfile(FIRST_PROFILE_ID);
const pubByProfileIdStruct = resultByProfileId.publicationStruct;
const profileByProfileIdStruct = resultByProfileId.profileStruct;
expect(profileStruct.pubCount).to.eq(2);
expect(profileStruct.followModule).to.eq(ZERO_ADDRESS);
expect(profileStruct.followNFT).to.eq(ZERO_ADDRESS);
expect(profileStruct.handle).to.eq(MOCK_PROFILE_HANDLE);
expect(profileStruct.imageURI).to.eq(MOCK_PROFILE_URI);
expect(profileStruct.followNFTURI).to.eq(MOCK_FOLLOW_NFT_URI);
expect(profileByProfileIdStruct.pubCount).to.eq(2);
expect(profileByProfileIdStruct.followModule).to.eq(ZERO_ADDRESS);
expect(profileByProfileIdStruct.followNFT).to.eq(ZERO_ADDRESS);
expect(profileByProfileIdStruct.handle).to.eq(MOCK_PROFILE_HANDLE);
expect(profileByProfileIdStruct.imageURI).to.eq(MOCK_PROFILE_URI);
expect(profileByProfileIdStruct.followNFTURI).to.eq(MOCK_FOLLOW_NFT_URI);
expect(pubStruct.profileIdPointed).to.eq(0);
expect(pubStruct.pubIdPointed).to.eq(0);
expect(pubStruct.contentURI).to.eq(secondURI);
expect(pubStruct.referenceModule).to.eq(ZERO_ADDRESS);
expect(pubStruct.collectModule).to.eq(emptyCollectModule.address);
expect(pubStruct.collectNFT).to.eq(ZERO_ADDRESS);
expect(pubByProfileIdStruct.profileIdPointed).to.eq(0);
expect(pubByProfileIdStruct.pubIdPointed).to.eq(0);
expect(pubByProfileIdStruct.contentURI).to.eq(secondURI);
expect(pubByProfileIdStruct.referenceModule).to.eq(ZERO_ADDRESS);
expect(pubByProfileIdStruct.collectModule).to.eq(emptyCollectModule.address);
expect(pubByProfileIdStruct.collectNFT).to.eq(ZERO_ADDRESS);
// `getLatestDataByHandle`, validate the result from the data provider
const resultByHandle = await dataProvider.getLatestDataByHandle(MOCK_PROFILE_HANDLE);
const pubByHandleStruct = resultByHandle.publicationStruct;
const profileByHandleStruct = resultByHandle.profileStruct;
expect(profileByHandleStruct.pubCount).to.eq(2);
expect(profileByHandleStruct.followModule).to.eq(ZERO_ADDRESS);
expect(profileByHandleStruct.followNFT).to.eq(ZERO_ADDRESS);
expect(profileByHandleStruct.handle).to.eq(MOCK_PROFILE_HANDLE);
expect(profileByHandleStruct.imageURI).to.eq(MOCK_PROFILE_URI);
expect(profileByHandleStruct.followNFTURI).to.eq(MOCK_FOLLOW_NFT_URI);
expect(pubByHandleStruct.profileIdPointed).to.eq(0);
expect(pubByHandleStruct.pubIdPointed).to.eq(0);
expect(pubByHandleStruct.contentURI).to.eq(secondURI);
expect(pubByHandleStruct.referenceModule).to.eq(ZERO_ADDRESS);
expect(pubByHandleStruct.collectModule).to.eq(emptyCollectModule.address);
expect(pubByHandleStruct.collectNFT).to.eq(ZERO_ADDRESS);
});
});
});