Skip to content

Commit 6ea2c2b

Browse files
committed
test: basic marketplace land integration test
1 parent a63c971 commit 6ea2c2b

File tree

10 files changed

+361
-10
lines changed

10 files changed

+361
-10
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {DeployFunction} from 'hardhat-deploy/types';
2+
import {HardhatRuntimeEnvironment} from 'hardhat/types';
3+
4+
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5+
const {deployments, getNamedAccounts} = hre;
6+
const {deploy} = deployments;
7+
8+
const {deployer, upgradeAdmin} = await getNamedAccounts();
9+
10+
const TRUSTED_FORWARDER_V2 = await deployments.get('TRUSTED_FORWARDER_V2');
11+
12+
await deploy('PolygonLand', {
13+
from: deployer,
14+
contract:
15+
'@sandbox-smart-contracts/core/src/solc_0.8/polygon/child/land/PolygonLandV2.sol:PolygonLandV2',
16+
proxy: {
17+
owner: upgradeAdmin,
18+
proxyContract: 'OpenZeppelinTransparentProxy',
19+
execute: {
20+
methodName: 'initialize',
21+
args: [TRUSTED_FORWARDER_V2.address],
22+
},
23+
upgradeIndex: 0,
24+
},
25+
log: true,
26+
});
27+
};
28+
export default func;
29+
func.tags = ['PolygonLand', 'PolygonLand_deploy', 'L2'];
30+
func.dependencies = ['TRUSTED_FORWARDER_V2'];
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {DeployFunction} from 'hardhat-deploy/types';
2+
import {HardhatRuntimeEnvironment} from 'hardhat/types';
3+
4+
export const royaltyAmount = 500;
5+
6+
const func: DeployFunction = async function (
7+
hre: HardhatRuntimeEnvironment
8+
): Promise<void> {
9+
const {deployments, getNamedAccounts} = hre;
10+
const {execute, read, catchUnknownSigner} = deployments;
11+
12+
const {sandAdmin} = await getNamedAccounts();
13+
const currentAdmin = await read('PolygonLand', {}, 'getAdmin');
14+
if (currentAdmin !== sandAdmin) {
15+
await catchUnknownSigner(
16+
execute(
17+
'PolygonLand',
18+
{from: currentAdmin, log: true},
19+
'changeAdmin',
20+
sandAdmin
21+
)
22+
);
23+
}
24+
};
25+
26+
export default func;
27+
func.tags = ['PolygonLand', 'PolygonLand_setup', 'L2'];
28+
func.dependencies = ['PolygonLand_deploy'];

packages/deploy/deploy/400_asset/401_deploy_asset_auth_validator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
88
const {deployer, assetAdmin} = await getNamedAccounts();
99
await deploy('AuthSuperValidator', {
1010
from: deployer,
11-
contract: 'AuthSuperValidator',
11+
contract:
12+
'@sandbox-smart-contracts/asset-1.0.3/contracts/AuthSuperValidator.sol:AuthSuperValidator',
1213
args: [assetAdmin],
1314
log: true,
1415
});

packages/deploy/deploy/500_marketplace/504_deploy_exchange.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ func.tags = ['Exchange', 'Exchange_deploy'];
4545
func.dependencies = [
4646
'RoyaltiesRegistry_deploy',
4747
'OrderValidator_deploy',
48+
'OrderValidator_setup',
4849
'TRUSTED_FORWARDER_V2',
4950
];

packages/deploy/hardhat.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const importedPackages = {
2424
'@sandbox-smart-contracts/dependency-operator-filter': 'contracts/',
2525
'@sandbox-smart-contracts/dependency-royalty-management': 'contracts/',
2626
'@sandbox-smart-contracts/core': [
27+
'/src/solc_0.8/polygon/child/land/PolygonLandV2.sol',
2728
'/src/solc_0.8/polygon/child/sand/PolygonSand.sol',
2829
'/src/solc_0.8/test/FakeChildChainManager.sol',
2930
],
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import {getContract, withSnapshot} from '../../utils/testUtils';
2+
import {expect} from 'chai';
3+
import {ethers} from 'hardhat';
4+
import {BigNumber} from 'ethers';
5+
import {AssetERC20, AssetERC721, OrderDefault, signOrder} from './orders';
6+
7+
const setupTest = withSnapshot(
8+
['Exchange', 'PolygonSand', 'PolygonLand'],
9+
async (hre) => {
10+
const {sandAdmin} = await hre.getNamedAccounts();
11+
const [user1, user2, minter] = await hre.getUnnamedAccounts();
12+
13+
const sandContract = await getContract(hre, 'PolygonSand');
14+
15+
const sandAdminSigner = await ethers.getSigner(sandAdmin);
16+
const landContract = await getContract(hre, 'PolygonLand', sandAdminSigner);
17+
await landContract.setMinter(minter, true);
18+
const landContractAsMinter = await landContract.connect(
19+
await ethers.getSigner(minter)
20+
);
21+
22+
const childChainManager = await getContract(
23+
hre,
24+
'CHILD_CHAIN_MANAGER',
25+
sandAdminSigner
26+
);
27+
await childChainManager.setPolygonAsset(landContract.address);
28+
29+
const exchangeAsUser2 = await getContract(
30+
hre,
31+
'Exchange',
32+
await ethers.getSigner(user2)
33+
);
34+
const orderValidatorAsAdmin = await getContract(
35+
hre,
36+
'OrderValidator',
37+
await ethers.getSigner(sandAdmin)
38+
);
39+
const TSB_ROLE = await orderValidatorAsAdmin.TSB_ROLE();
40+
// enable land in whitelist
41+
await orderValidatorAsAdmin.grantRole(
42+
TSB_ROLE,
43+
landContractAsMinter.address
44+
);
45+
return {
46+
landContract,
47+
landContractAsMinter,
48+
sandContract,
49+
exchangeAsUser2,
50+
orderValidatorAsAdmin,
51+
sandAdmin,
52+
user1,
53+
user2,
54+
minter,
55+
mintSand: async (user: string, amount: BigNumber) =>
56+
childChainManager.callSandDeposit(
57+
sandContract.address,
58+
user,
59+
ethers.utils.defaultAbiCoder.encode(['uint256'], [amount])
60+
),
61+
};
62+
}
63+
);
64+
65+
describe('Marketplace Land <-> Sand exchange', function () {
66+
it('simple exchange', async function () {
67+
const {
68+
sandContract,
69+
landContractAsMinter,
70+
exchangeAsUser2,
71+
orderValidatorAsAdmin,
72+
user1,
73+
user2,
74+
mintSand,
75+
} = await setupTest();
76+
const oneEth = ethers.utils.parseEther('1');
77+
const landTokenId = 0;
78+
const size = 1;
79+
await landContractAsMinter.mintQuad(user1, size, 0, 0, '0x');
80+
expect(await landContractAsMinter.balanceOf(user1)).to.be.equal(
81+
size * size
82+
);
83+
84+
await mintSand(user2, oneEth);
85+
expect(await sandContract.balanceOf(user2)).to.be.equal(oneEth);
86+
87+
await sandContract
88+
.connect(await ethers.getSigner(user2))
89+
.approve(exchangeAsUser2.address, oneEth);
90+
await landContractAsMinter
91+
.connect(await ethers.getSigner(user1))
92+
.approve(exchangeAsUser2.address, landTokenId);
93+
94+
const makerAsset = await AssetERC721(landContractAsMinter, landTokenId);
95+
const takerAsset = await AssetERC20(sandContract, oneEth);
96+
const orderLeft = OrderDefault(
97+
user1,
98+
makerAsset,
99+
ethers.constants.AddressZero,
100+
takerAsset,
101+
1,
102+
0,
103+
0
104+
);
105+
const orderRight = await OrderDefault(
106+
user2,
107+
takerAsset,
108+
ethers.constants.AddressZero,
109+
makerAsset,
110+
1,
111+
0,
112+
0
113+
);
114+
const makerSig = await signOrder(orderLeft, user1, orderValidatorAsAdmin);
115+
const takerSig = await signOrder(orderRight, user2, orderValidatorAsAdmin);
116+
const tx = await exchangeAsUser2.matchOrders([
117+
{
118+
orderLeft,
119+
signatureLeft: makerSig,
120+
orderRight,
121+
signatureRight: takerSig,
122+
},
123+
]);
124+
const receipt = await tx.wait();
125+
console.log(receipt.gasUsed.toString());
126+
expect(await landContractAsMinter.balanceOf(user2)).to.be.equal(
127+
size * size
128+
);
129+
expect(await sandContract.balanceOf(user1)).to.be.equal(oneEth);
130+
});
131+
});
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import {ethers} from 'hardhat';
2+
import {BigNumber, BigNumberish, Contract} from 'ethers';
3+
4+
export const ASSET_TYPE_TYPEHASH = ethers.utils.keccak256(
5+
ethers.utils.toUtf8Bytes('AssetType(uint256 assetClass,bytes data)')
6+
);
7+
8+
export function hashAssetType(a: AssetType) {
9+
if (a.assetClass === AssetClassType.INVALID_ASSET_CLASS) {
10+
throw new Error('Invalid assetClass' + a.assetClass);
11+
}
12+
return ethers.utils.keccak256(
13+
ethers.utils.defaultAbiCoder.encode(
14+
['bytes32', 'uint256', 'bytes32'],
15+
[ASSET_TYPE_TYPEHASH, a.assetClass, ethers.utils.keccak256(a.data)]
16+
)
17+
);
18+
}
19+
20+
export function hashKey(order: Order): string {
21+
const encoded = ethers.utils.defaultAbiCoder.encode(
22+
['address', 'bytes32', 'bytes32', 'uint256'],
23+
[
24+
order.maker,
25+
hashAssetType(order.makeAsset.assetType),
26+
hashAssetType(order.takeAsset.assetType),
27+
order.salt,
28+
]
29+
);
30+
return ethers.utils.keccak256(encoded);
31+
}
32+
33+
export async function signOrder(
34+
order: Order,
35+
account: string,
36+
verifyingContract: Contract
37+
) {
38+
const network = await verifyingContract.provider.getNetwork();
39+
return await ethers.provider.send('eth_signTypedData_v4', [
40+
account,
41+
{
42+
types: {
43+
EIP712Domain: [
44+
{
45+
name: 'name',
46+
type: 'string',
47+
},
48+
{
49+
name: 'version',
50+
type: 'string',
51+
},
52+
{
53+
name: 'chainId',
54+
type: 'uint256',
55+
},
56+
{
57+
name: 'verifyingContract',
58+
type: 'address',
59+
},
60+
],
61+
AssetType: [
62+
{name: 'assetClass', type: 'uint256'},
63+
{name: 'data', type: 'bytes'},
64+
],
65+
Asset: [
66+
{name: 'assetType', type: 'AssetType'},
67+
{name: 'value', type: 'uint256'},
68+
],
69+
Order: [
70+
{name: 'maker', type: 'address'},
71+
{name: 'makeAsset', type: 'Asset'},
72+
{name: 'taker', type: 'address'},
73+
{name: 'takeAsset', type: 'Asset'},
74+
{name: 'salt', type: 'uint256'},
75+
{name: 'start', type: 'uint256'},
76+
{name: 'end', type: 'uint256'},
77+
],
78+
},
79+
primaryType: 'Order',
80+
domain: {
81+
name: 'The Sandbox Marketplace',
82+
version: '1.0.0',
83+
chainId: network.chainId,
84+
verifyingContract: verifyingContract.address,
85+
},
86+
message: order,
87+
},
88+
]);
89+
}
90+
91+
export type Order = {
92+
maker: string;
93+
makeAsset: Asset;
94+
taker: string;
95+
takeAsset: Asset;
96+
salt: string;
97+
start: string;
98+
end: string;
99+
};
100+
101+
export const OrderDefault = (
102+
maker: string,
103+
makeAsset: Asset,
104+
taker: string,
105+
takeAsset: Asset,
106+
salt: BigNumberish,
107+
start: BigNumberish,
108+
end: BigNumberish
109+
): Order => ({
110+
maker: maker,
111+
makeAsset,
112+
taker: taker,
113+
takeAsset,
114+
salt: BigNumber.from(salt).toString(),
115+
start: BigNumber.from(start).toString(),
116+
end: BigNumber.from(end).toString(),
117+
});
118+
119+
export enum AssetClassType {
120+
INVALID_ASSET_CLASS = '0x0',
121+
ERC20_ASSET_CLASS = '0x1',
122+
ERC721_ASSET_CLASS = '0x2',
123+
ERC1155_ASSET_CLASS = '0x3',
124+
}
125+
126+
export type AssetType = {
127+
assetClass: AssetClassType;
128+
data: string;
129+
};
130+
export type Asset = {
131+
assetType: AssetType;
132+
value: string;
133+
};
134+
export const AssetERC20 = async (
135+
tokenContract: Contract,
136+
value: BigNumberish
137+
): Promise<Asset> => ({
138+
assetType: {
139+
assetClass: AssetClassType.ERC20_ASSET_CLASS,
140+
data: ethers.utils.defaultAbiCoder.encode(
141+
['address'],
142+
[tokenContract.address]
143+
),
144+
},
145+
value: BigNumber.from(value).toString(),
146+
});
147+
export const AssetERC721 = async (
148+
tokenContract: Contract,
149+
tokenId: BigNumberish
150+
): Promise<Asset> => ({
151+
assetType: {
152+
assetClass: AssetClassType.ERC721_ASSET_CLASS,
153+
data: ethers.utils.defaultAbiCoder.encode(
154+
['address', 'uint256'],
155+
[tokenContract.address, BigNumber.from(tokenId)]
156+
),
157+
},
158+
value: BigNumber.from(1).toString(),
159+
});

packages/deploy/runtime_test/multiGiveaway/multiGiveaway.test.ts renamed to packages/deploy/runtime_test/multiGiveaway.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {getContract, withSnapshot} from '../../utils/testUtils';
1+
import {getContract, withSnapshot} from '../utils/testUtils';
22
import {expect} from 'chai';
33

44
const setupTest = withSnapshot(['SignedMultiGiveaway'], async (hre) => {

0 commit comments

Comments
 (0)