-
Notifications
You must be signed in to change notification settings - Fork 808
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* test * test * add more setup * add to path * githubpath * seid path * dapp tests * try artifacts * ditch setup step * deps * test workflow * set keyring * without * keys add * add to sh * nobackend * no script * test * keyring * no sh * test * fix flakiness * cleanup * move seid config command * only if docker * test without * if isdocker * printf mnemonic * try escape path * try single quotes * try modifying execute * no path * backend * try without keyring * move keyring * path * basedir * try pwd * config reset * seid config * redeclare * print * docker path * dynamic path * config for all * full * lint issue * backend * cleanup * seaport starter * working locally * working on all chains * add readme * keyring * stray argument in unit test * cleanup * reduce costs * scripts
- Loading branch information
Showing
13 changed files
with
599 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# dApp Tests | ||
|
||
This directory contains integration tests that simulate simple use cases on the chain by deploying and running common dApp contracts. | ||
The focus here is mainly on testing common interop scenarios (interactions with associated/unassociated accounts, pointer contracts etc.) | ||
In each test scenario, we deploy the dapp contracts, fund wallets, then go through common end to end scenarios. | ||
|
||
## Setup | ||
To run the dapp tests, simply run the script at `/integration_test/dapp_tests/dapp_tests.sh <chain>` | ||
|
||
3 chain types are supported, `seilocal`, `devnet` (arctic-1) and `testnet` (atlantic-2). The configs for each chain are stored in `./hardhat.config.js`. | ||
|
||
If running on `seilocal`, the script assumes that a local instance of the chain is running by running `/scripts/initialize_local_chain.sh`. | ||
A well funded `admin` account must be available on the local keyring. | ||
|
||
If running on the live chains, the tests rely on a `deployer` account, which has to have sufficient funds on the chain the test is running on. | ||
The deployer mnemonic must be stored as an environment variable: DAPP_TESTS_MNEMONIC. | ||
On the test pipelines, the account used is: | ||
- Deployer Sei address: `sei1rtpakm7w9egh0n7xngzm6vrln0szv6yeva6hhn` | ||
- Deployer EVM address: `0x4D952b770C3a0B096e739399B40263D0b516d406` | ||
|
||
## Tests | ||
|
||
### Uniswap (EVM DEX) | ||
This test deploys a small set of UniswapV3 contracts to the EVM and tests swapping and creation of uniswap pools. | ||
- Test that associated accounts are able to swap erc20 tokens | ||
- Test that associated accounts are able to swap native tokens via pointer | ||
- Test that associated accounts are able to swap cw20 tokens via pointer | ||
- Test that unassociated accounts are able to receive erc20 tokens | ||
- Test that unassociated accounts are able to receive native tokens via pointer | ||
- Unassociated EVM accounts are not able to receive cw20 tokens via pointer | ||
- Test that unassociated accounts can still deploy and supply erc20-erc20pointer liquidity pools. | ||
|
||
### Steak (CW Liquid Staking) | ||
This test deploys a set of WASM liquid staking contracts, then tests bonding and unbonding. | ||
- Test that associated accounts are able to bond, then unbond tokens. | ||
- Test that unassociated accounts are able to bond, then unbond tokens. | ||
|
||
### NFT Marketplace (EVM NFT Marketplace) | ||
This test deploys a simple NFT Marketplace contract, then tests listing and buying NFTs. | ||
- Test that associated accounts are able to list and buy erc721 tokens | ||
- Test that unassociated accounts are able to list and buy erc721 tokens | ||
- Test that associated accounts are able to buy cw721 tokens via pointers | ||
- Unassociated EVM accounts are currently unable to own or receive cw721 tokens via pointers | ||
|
||
### To Be Added | ||
The following is a list of testcases/scenarios that we should add to verify completeness | ||
- CosmWasm DEX tests - test that ERC20 tokens are tradeable via pointer contracts. | ||
- CosmWasm NFT Marketplace tests - test that ERC721 tokens are tradeable via pointer contracts. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; | ||
|
||
contract MockERC721 is ERC721, ERC721Enumerable, Ownable { | ||
uint256 private _currentTokenId = 0; | ||
|
||
constructor(string memory name, string memory symbol) ERC721(name, symbol) Ownable(msg.sender) {} | ||
|
||
function mint(address to) public onlyOwner { | ||
_currentTokenId++; | ||
_mint(to, _currentTokenId); | ||
} | ||
|
||
function batchMint(address to, uint256 amount) public onlyOwner { | ||
for (uint256 i = 0; i < amount; i++) { | ||
_currentTokenId++; | ||
_mint(to, _currentTokenId); | ||
} | ||
} | ||
|
||
function burn(uint256 tokenId) public { | ||
_burn(tokenId); | ||
} | ||
|
||
// The following functions are overrides required by Solidity. | ||
|
||
function _update(address to, uint256 tokenId, address auth) | ||
internal | ||
override(ERC721, ERC721Enumerable) | ||
returns (address) | ||
{ | ||
return super._update(to, tokenId, auth); | ||
} | ||
|
||
function _increaseBalance(address account, uint128 value) | ||
internal | ||
override(ERC721, ERC721Enumerable) | ||
{ | ||
super._increaseBalance(account, value); | ||
} | ||
|
||
function supportsInterface(bytes4 interfaceId) | ||
public | ||
view | ||
override(ERC721, ERC721Enumerable) | ||
returns (bool) | ||
{ | ||
return super.supportsInterface(interfaceId); | ||
} | ||
} |
163 changes: 163 additions & 0 deletions
163
integration_test/dapp_tests/contracts/NftMarketplace.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.20; | ||
|
||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | ||
|
||
/* | ||
* @title NftMarketplace | ||
* @auth Patrick Collins | ||
* @notice This contract allows users to list NFTs for sale | ||
* @notice This is the reference | ||
*/ | ||
contract NftMarketplace { | ||
error NftMarketplace__PriceNotMet(address nftAddress, uint256 tokenId, uint256 price); | ||
error NftMarketplace__NotListed(address nftAddress, uint256 tokenId); | ||
error NftMarketplace__NoProceeds(); | ||
error NftMarketplace__NotOwner(); | ||
error NftMarketplace__PriceMustBeAboveZero(); | ||
error NftMarketplace__TransferFailed(); | ||
|
||
event ItemListed(address indexed seller, address indexed nftAddress, uint256 indexed tokenId, uint256 price); | ||
event ItemUpdated(address indexed seller, address indexed nftAddress, uint256 indexed tokenId, uint256 price); | ||
event ItemCanceled(address indexed seller, address indexed nftAddress, uint256 indexed tokenId); | ||
event ItemBought(address indexed buyer, address indexed nftAddress, uint256 indexed tokenId, uint256 price); | ||
|
||
mapping(address nftAddress => mapping(uint256 tokenId => Listing)) private s_listings; | ||
mapping(address seller => uint256 proceedAmount) private s_proceeds; | ||
|
||
struct Listing { | ||
uint256 price; | ||
address seller; | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
/* | ||
* @notice Method for listing NFT | ||
* @param nftAddress Address of NFT contract | ||
* @param tokenId Token ID of NFT | ||
* @param price sale price for each item | ||
*/ | ||
function listItem(address nftAddress, uint256 tokenId, uint256 price) external { | ||
// Checks | ||
if (price <= 0) { | ||
revert NftMarketplace__PriceMustBeAboveZero(); | ||
} | ||
|
||
// Effects (Internal) | ||
s_listings[nftAddress][tokenId] = Listing(price, msg.sender); | ||
emit ItemListed(msg.sender, nftAddress, tokenId, price); | ||
|
||
// Interactions (External) | ||
IERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenId); | ||
} | ||
|
||
/* | ||
* @notice Method for cancelling listing | ||
* @param nftAddress Address of NFT contract | ||
* @param tokenId Token ID of NFT | ||
* | ||
* @audit-known seller can front-run a bought NFT and cancel the listing | ||
*/ | ||
function cancelListing(address nftAddress, uint256 tokenId) external { | ||
// Checks | ||
if (msg.sender != s_listings[nftAddress][tokenId].seller) { | ||
revert NftMarketplace__NotOwner(); | ||
} | ||
|
||
// Effects (Internal) | ||
delete s_listings[nftAddress][tokenId]; | ||
emit ItemCanceled(msg.sender, nftAddress, tokenId); | ||
|
||
// Interactions (External) | ||
IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenId); | ||
} | ||
|
||
/* | ||
* @notice Method for buying listing | ||
* @notice The owner of an NFT could unapprove the marketplace, | ||
* @param nftAddress Address of NFT contract | ||
* @param tokenId Token ID of NFT | ||
*/ | ||
function buyItem(address nftAddress, uint256 tokenId) external payable { | ||
Listing memory listedItem = s_listings[nftAddress][tokenId]; | ||
// Checks | ||
if (listedItem.seller == address(0)) { | ||
revert NftMarketplace__NotListed(nftAddress, tokenId); | ||
} | ||
if (msg.value < listedItem.price) { | ||
revert NftMarketplace__PriceNotMet(nftAddress, tokenId, listedItem.price); | ||
} | ||
|
||
// Effects (Internal) | ||
s_proceeds[listedItem.seller] += msg.value; | ||
delete s_listings[nftAddress][tokenId]; | ||
emit ItemBought(msg.sender, nftAddress, tokenId, listedItem.price); | ||
|
||
// Interactions (External) | ||
IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenId); | ||
} | ||
|
||
/* | ||
* @notice Method for updating listing | ||
* @param nftAddress Address of NFT contract | ||
* @param tokenId Token ID of NFT | ||
* @param newPrice Price in Wei of the item | ||
* | ||
* @audit-known seller can front-run a bought NFT and update the listing | ||
*/ | ||
function updateListing(address nftAddress, uint256 tokenId, uint256 newPrice) external { | ||
// Checks | ||
if (newPrice <= 0) { | ||
revert NftMarketplace__PriceMustBeAboveZero(); | ||
} | ||
if (msg.sender != s_listings[nftAddress][tokenId].seller) { | ||
revert NftMarketplace__NotOwner(); | ||
} | ||
|
||
// Effects (Internal) | ||
s_listings[nftAddress][tokenId].price = newPrice; | ||
emit ItemUpdated(msg.sender, nftAddress, tokenId, newPrice); | ||
} | ||
|
||
/* | ||
* @notice Method for withdrawing proceeds from sales | ||
* | ||
* @audit-known, we should emit an event for withdrawing proceeds | ||
*/ | ||
function withdrawProceeds() external { | ||
uint256 proceeds = s_proceeds[msg.sender]; | ||
// Checks | ||
if (proceeds <= 0) { | ||
revert NftMarketplace__NoProceeds(); | ||
} | ||
// Effects (Internal) | ||
s_proceeds[msg.sender] = 0; | ||
|
||
// Interactions (External) | ||
(bool success,) = payable(msg.sender).call{value: proceeds}(""); | ||
if (!success) { | ||
revert NftMarketplace__TransferFailed(); | ||
} | ||
} | ||
|
||
function onERC721Received(address, /*operator*/ address, /*from*/ uint256, /*tokenId*/ bytes calldata /*data*/ ) | ||
external | ||
pure | ||
returns (bytes4) | ||
{ | ||
return this.onERC721Received.selector; | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
VIEW/PURE FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
function getListing(address nftAddress, uint256 tokenId) external view returns (Listing memory) { | ||
return s_listings[nftAddress][tokenId]; | ||
} | ||
|
||
function getProceeds(address seller) external view returns (uint256) { | ||
return s_proceeds[seller]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Oops, something went wrong.