Skip to content

Commit

Permalink
doc: added README for land-sale package
Browse files Browse the repository at this point in the history
  • Loading branch information
capedcrusader21 committed Nov 19, 2024
1 parent 154fc72 commit 479698c
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
8 changes: 7 additions & 1 deletion packages/land-sale/.solcover.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
],
};
96 changes: 96 additions & 0 deletions packages/land-sale/README.md
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions packages/land-sale/test/EstateSaleWithAuth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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();
Expand All @@ -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();

Expand All @@ -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 () {
Expand All @@ -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(
Expand All @@ -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();
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -90,13 +98,15 @@ 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(
buyLand({buyer: landBuyer, landIndex: 3}),
).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 {
Expand All @@ -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();
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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} =
Expand All @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions packages/land-sale/test/referral-validator-setup.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down

1 comment on commit 479698c

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage for this commit

90.32%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
packages/land-sale/contracts
   EstateSaleWithAuth.sol80.33%68.18%75%90.32%109, 125, 166, 166, 169, 259–266, 63, 74, 80, 88, 88, 88–89
packages/land-sale/contracts/common/Interfaces
   ERC1155.sol100%100%100%100%
   ERC165.sol100%100%100%100%
   ERC20.sol100%100%100%100%
   ERC20WithMetadata.sol100%100%100%100%
   ERC721.sol100%100%100%100%
   ERC721Events.sol100%100%100%100%
   ILandToken.sol100%100%100%100%

Please sign in to comment.