From 479698cb832e80cac69ff371df6c0b817def47c1 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Tue, 19 Nov 2024 16:10:56 +0530 Subject: [PATCH] doc: added README for land-sale package --- packages/land-sale/.solcover.js | 8 +- packages/land-sale/README.md | 96 +++++++++++++++++++ .../land-sale/test/EstateSaleWithAuth.test.ts | 16 ++++ .../test/referral-validator-setup.ts | 3 +- 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 packages/land-sale/README.md diff --git a/packages/land-sale/.solcover.js b/packages/land-sale/.solcover.js index f6c4e5445d..a7bd7bab09 100644 --- a/packages/land-sale/.solcover.js +++ b/packages/land-sale/.solcover.js @@ -3,5 +3,11 @@ module.exports = { grep: '@skip-on-coverage', // Find everything with this tag invert: true, // Run the grep's inverse set. }, - skipFiles: ['/mock'], + skipFiles: [ + '/mocks', + '/AuthValidator.sol', + 'common/BaseWithStorage', + 'common/Libraries/SafeMathWithRequire.sol', + 'ReferralValidator/ReferralValidator.sol', + ], }; diff --git a/packages/land-sale/README.md b/packages/land-sale/README.md new file mode 100644 index 0000000000..a9a6855914 --- /dev/null +++ b/packages/land-sale/README.md @@ -0,0 +1,96 @@ +# land-sale + +The land-sale package outlines the process for deploying Land Presale smart +contracts for The Sandbox's metaverse. + +## Architecture + +This package is used to deploy smart contracts for Land sales. The package +contains 2 main contracts: + +| Component | Description | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------- | +| [AuthValidator](contracts/AuthValidator.sol) | contract which verifies that only a trusted wallet can authorize land sale actions | +| [EstateSaleWithAuth](contracts/EstateSaleWithAuth.sol) | contract used to create and manage land sales in the metaverse. | + +- It leverages two key files: +- **bundles.testnet.json**: Specifies optional asset bundles sold with certain + Lands. +- **sectors.testnet.json**: Defines the sectors being deployed. +- Deploy a new Land Presale contract for each sector using the + `EstateSaleWithAuth` template, as shown in the deploy script. +- **No need for new deploy scripts**: Instead of creating a new deploy script + for each sale, the existing script is updated with the new sectors. +- **Set a Deadline**: A deadline must be specified in + `packages/land-sale/data/deadlines.ts`. +- For mainnet deadline will be of six months and for testnet this deadline is + ignored by the script. + +## Getting Started + +### Step 1: Prepare for Deployment + +- **Receive JSON Files**: The Landsale team will provide `bundles.testnet.json` + and `sectors.testnet.json` files. +- **Organize the Files**: Place the JSON files in a new folder within + `data/land-sale` named `LandPreSale_XX`. +- **NOTE**: Here, `XX` is an incremented folder number that does not correspond + to sector numbers. + +### Step 2: Manage Secrets + +- The mainnet secret **must be different** from the testnet secret. The secret + content can be any unique value. + +--- + +## Sample files + +### bundles.test.json : + +``` +{ + "bundleId": [ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + ] +} +``` + +### sectors.testnet.json : + +``` +[ + { + "sector": 0, + "lands": [ + { + "coordinateX": xx, + "coordinateY": yy, + "ownerAddress": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "bundleId": "" + } + ] + } +] +``` + +### deadlines.ts : + +``` +XX: new Date('YYYY-MM-DDT12:00:00.000Z').valueOf() / 1000 +``` + +--- + +## Running the project locally + +Install dependencies with `yarn` + +To execute the deployment, run + +- for fork deployment: + `yarn fork:deploy --network NETWORK --tags TAG --no-impersonation` +- for live deployment: `yarn live:deploy --network NETWORK --tags TAG` +- where: +- `NETWORK` is the network name like: `polygon`, `mainet` etc +- `TAG` are the tags used to limit which deployment scripts will be executed diff --git a/packages/land-sale/test/EstateSaleWithAuth.test.ts b/packages/land-sale/test/EstateSaleWithAuth.test.ts index 5134e96b1f..d02af66236 100644 --- a/packages/land-sale/test/EstateSaleWithAuth.test.ts +++ b/packages/land-sale/test/EstateSaleWithAuth.test.ts @@ -7,6 +7,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s const {deployEstateSaleContract} = await runEstateSaleSetup(); await expect(deployEstateSaleContract()).to.not.be.reverted; }); + describe('Functions', function () { describe('setReceivingWallet', function () { it('should allow admin to set new receving wallet', async function () { @@ -22,6 +23,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s .to.emit(EstateSaleContractAsAdmin, 'NewReceivingWallet') .withArgs(newLandSaleBeneficiary.address); }); + it('should not allow non-admin to set new receving wallet', async function () { const {EstateSaleContract, newLandSaleBeneficiary} = await runEstateSaleSetup(); @@ -32,6 +34,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s await expect(tx).to.be.revertedWith('NOT_AUTHORIZED'); }); + it('should not allow admin to set new receving wallet to the zero address', async function () { const {EstateSaleContractAsAdmin} = await runEstateSaleSetup(); @@ -41,6 +44,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s await expect(tx).to.be.revertedWith('ZERO_ADDRESS'); }); }); + describe('buyLandWithSand', function () { describe('Reverts', function () { it('should revert if the sale is over', async function () { @@ -55,6 +59,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.be.revertedWith('SALE_IS_OVER'); }); + it('should revert if the buyer is not the sender', async function () { const {buyLand, landBuyer2, landBuyer} = await runEstateSaleSetup(); await expect( @@ -64,6 +69,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.be.revertedWith('NOT_AUTHORIZED'); }); + it('should revert if trying to buy a reserved land', async function () { const {buyLand, landBuyer, reservedLandIndex} = await runEstateSaleSetup(); @@ -74,6 +80,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.be.revertedWith('RESERVED_LAND'); }); + it('should revert if the signature is invalid', async function () { const {buyLand} = await runEstateSaleSetup(); await expect( @@ -82,6 +89,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.be.revertedWith('INVALID_AUTH'); }); + it('should revert if trying to purchase another land that the one from the proof', async function () { const {buyLand} = await runEstateSaleSetup(); await expect( @@ -90,6 +98,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.be.revertedWith('INVALID_LAND'); }); + it("shoudl revert if the buyer doesn't have enough funds", async function () { const {buyLand, landBuyer} = await runEstateSaleSetup(); await expect( @@ -97,6 +106,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s ).to.be.revertedWith('ERC20: transfer amount exceeds balance'); }); }); + describe('Success', function () { it('should send the 5% land fee to the specified address', async function () { const { @@ -115,6 +125,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s expect(balance).to.equal(fivePercentFee); }); + it('should NOT revert if the buyer is not the sender and IT IS a meta transaction', async function () { const {buyLand, trustedForwarder, landBuyer} = await runEstateSaleSetup(); @@ -125,6 +136,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.not.be.reverted; }); + it('should NOT revert if trying to buy a reserved land from correct account', async function () { const {buyLand, landBuyer2} = await runEstateSaleSetup(); await expect( @@ -134,10 +146,12 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s }), ).to.not.be.reverted; }); + it("should mint new land to the to's address", async function () { const {buyLand} = await runEstateSaleSetup(); await expect(buyLand()).to.not.be.reverted; }); + it("should send assets to the to's address for premium lands", async function () { const { buyLand, @@ -158,6 +172,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s expect(balance[0]).to.equal(1); }); }); + describe('Events', function () { it("should emit NewReceivingWallet with the new wallet's address", async function () { const {EstateSaleContractAsAdmin, newLandSaleBeneficiary} = @@ -169,6 +184,7 @@ describe('EstateSaleWithAuth (/packages/land-sale/contracts/EstateSaleWithAuth.s .to.emit(EstateSaleContractAsAdmin, 'NewReceivingWallet') .withArgs(newLandSaleBeneficiary.address); }); + it('should emit LandQuadPurchased with the buyers and land info', async function () { const { buyLand, diff --git a/packages/land-sale/test/referral-validator-setup.ts b/packages/land-sale/test/referral-validator-setup.ts index 182c522b10..f12566b743 100644 --- a/packages/land-sale/test/referral-validator-setup.ts +++ b/packages/land-sale/test/referral-validator-setup.ts @@ -1,8 +1,7 @@ import {ethers} from 'hardhat'; const referralValiatorSetup = async () => { - const [_, initialSigningWallet] = await ethers.getSigners(); - + const [initialSigningWallet] = await ethers.getSigners(); const ReferralValidatorFactory = await ethers.getContractFactory('ReferralValidator'); const initialMaxCommissionRate = 1000;