difftreelog
MarketPlace.sol from unique-marketplace
in: master
5 files changed
tests/src/eth/marketplace/MarketPlace.abidiffbeforeafterbothno changes
tests/src/eth/marketplace/MarketPlace.bindiffbeforeafterbothno changes
tests/src/eth/marketplace/MarketPlace.soldiffbeforeafterboth1// SPDX-License-Identifier: Apache License1// SPDX-License-Identifier: Apache License2pragma solidity >=0.8.0;2pragma solidity >=0.8.0;3import "../api/UniqueNFT.sol";3import {UniqueNFT, Dummy, ERC165} from "../api/UniqueNFT.sol";445// Inline5// Inline6interface ERC20Events {6interface ERC20Events {54 struct Order {54 struct Order {55 55 uint256 idNFT;56 uint256 idNFT;56 address currencyCode; // UNIQ tokens as address address (1); wKSM57 address currencyCode; // UNIQ tokens as address address (1); wKSM 57 uint256 price;58 uint256 price;58 uint256 time;59 uint256 time;59 address idCollection;60 address idCollection;64 string tokenURI;65 string tokenURI; 65 }66 }66 Order[] public orders;67 Order[] public orders;67 uint256 test;68 uint test;68 mapping(address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs]69 mapping (address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs]69 mapping(address => mapping(uint256 => uint256)) public asks; // [buyer][idCollection][idNFT] => idorder70 mapping (address => mapping (uint256 => uint256)) public asks ; // [buyer][idCollection][idNFT] => idorder71 mapping (address => mapping (uint => uint[])) public ordersbyNFT; // [addressCollection] =>idNFT =>idorder707271 mapping(address => uint256[]) public asksbySeller; // [addressSeller] =>idorder73 mapping (address => uint[]) public asksbySeller; // [addressSeller] =>idorder727473 address escrow;75 mapping (address =>bool) internal isEscrow;7677 //address escrow;74 address owner;78 address owner;75 address nativecoin;79 address nativecoin;768077 constructor(address _escrow) {81 // from abstract contract ReentrancyGuard 82 // Booleans are more expensive than uint256 or any type that takes up a full83 // word because each write operation emits an extra SLOAD to first read the84 // slot's contents, replace the bits taken up by the boolean, and then write85 // back. This is the compiler's defense against contract upgrades and86 // pointer aliasing, and it cannot be disabled.8788 // The values being non-zero value makes deployment a bit more expensive,89 // but in exchange the refund on every call to nonReentrant will be lower in90 // amount. Since refunds are capped to a percentage of the total91 // transaction's gas, it is best to keep them low in cases like this one, to92 // increase the likelihood of the full refund coming into effect.93 uint8 private constant _NOT_ENTERED = 1;78 escrow = _escrow;94 uint8 private constant _ENTERED = 2;9596 uint8 private _status;9798 struct NFT {99 address collection;100 uint256 id;101 }102 103 //function initialize() public initializer {104 constructor () { // call setEscrow directly79 owner = msg.sender;105 owner = msg.sender;8010681 orders.push(107 orders.push(Order( 82 Order(0, address(0), 0, 0, address(0), address(0), 0, "", "", "")108 0,109 address(0),110 0,111 0,112 address(0),113 address(0),83 );114 0, "","",""));84 }8586 function setowner(address _newEscrow) public onlyOwner {87 escrow = _newEscrow;115 _status = _NOT_ENTERED;88 }11689117 }118119 modifier nonReentrant() { // from abstract contract ReentrancyGuard 120 // On the first call to nonReentrant, _notEntered will be true90 function setEscrow(address _newEscrow) public onlyOwner {121 require(_status != _ENTERED, "ReentrancyGuard: reentrant call");91 escrow = _newEscrow;12292 }123 // Any calls to nonReentrant after this point will fail93124 _status = _ENTERED;94 function setNativeCoin(address _coin) public onlyOwner {125126 _;127128 // By storing the original value once again, a refund is triggered (see129 // https://eips.ethereum.org/EIPS/eip-2200)95 nativecoin = _coin;130 _status = _NOT_ENTERED;96 }131 }9713298 modifier onlyEscrow() {133 modifier onlyEscrow () {99 require(msg.sender == escrow, "Only escrow can");134 require(isEscrow [msg.sender] , "Only escrow can");100 _;135 _;101 }136 }102137105 _;140 _;106 }141 }107142108 /**143 /**109 * Make bids (orders) to sell NFTs144 * Make bids (orders) to sell NFTs 110 */145 */111146147 112 receive() external payable {148 receive () external payable {113 revert(149 // revert ("Can't accept payment without collection and IDs, use dApp to send");114 "Can't accept payment without collection and IDs, use dApp to send"115 );116 }150 }117118 fallback() external payable {151 fallback () external payable {132 address _idCollection,163 address _idCollection, 133 uint256 _idNFT,164 uint256 _idNFT,134 uint8 _active,165 uint8 _active,135 uint256 orderId166 uint orderId);136 );137167138 event CanceledAsk(address _idCollection, uint256 _idNFT, uint256 orderId);168 event CanceledAsk (address _idCollection, 169 uint256 _idNFT, 170 uint orderId171 );139172140 event DepositedKSM(uint256 _amount, address _sender);173 event DepositedKSM (uint256 _amount, address _sender);141174142 event BoughtNFT4KSM(175 event BoughtNFT4KSM (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );143 address _idCollection,144 uint256 _idNFT,145 uint256 orderID,146 uint256 orderPrice147 );148176149 event BoughtNFT(177 event BoughtNFT (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );150 address _idCollection,151 uint256 _idNFT,152 uint256 orderID,153 uint256 orderPrice154 );155178156 event WithdrawnAllKSM(address _sender, uint256 balance);179 event WithdrawnAllKSM (address _sender, uint256 balance); 180181 event WithdrawnKSM (address _sender, uint256 balance); 157182158 event Withdrawn(uint256 _amount, address _currencyCode, address _sender);183 event Withdrawn (uint256 _amount, address _currencyCode, address _sender);184 185186 function setOwner (address _newOwner) public onlyOwner {187 owner = _newOwner;188 }189190 function setEscrow (address _escrow, bool _state) public onlyOwner returns (bool) {191 if (isEscrow[_escrow] != _state) {192 isEscrow[_escrow] = _state;193 return true;194 }195 return false;196 }197198 function setNativeCoin (address _coin) public onlyOwner {199 nativecoin = _coin;200 }201159202160 function addAsk(203 function addAsk (uint256 _price, 201 )242 ));202 );243 203204 uint256 orderId = orders.length - 1;244 uint orderId = orders.length-1;205 asks[_idCollection][_idNFT] = orderId;245 asks[_idCollection][_idNFT] = orderId;206 asksbySeller[msg.sender].push(orderId);246 asksbySeller[msg.sender].push(orderId);207 UniqueNFT(_idCollection).transferFrom(247 UniqueNFT(_idCollection).transferFrom(msg.sender, address(this), _idNFT);220 uint8 _active255 uint8 _active) public {221 ) public {256 257222 uint256 orderID = asks[_idCollection][_idNFT];258 uint orderID = asks[_idCollection][_idNFT];223259224 require(260 require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");225 orders[orderID].ownerAddr == msg.sender,278 uint256 _idNFT279 ) public {280251 uint256 orderID = asks[_idCollection][_idNFT];281 uint orderID = asks[_idCollection][_idNFT];252282253 require(283 require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");254 orders[orderID].ownerAddr == msg.sender,278 address _receiver279 ) public {280 Order memory order = orders[asks[_idCollection][_idNFT]];300 Order memory order = orders[ asks[_idCollection][_idNFT]];281 require(msg.sender == escrow || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" );301 require(isEscrow[msg.sender] || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" );282 //1. reduce balance302 //1. reduce balance303283 balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;304 balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;294 );295 }312 }296297 function buy(address _idCollection, uint256 _idNFT)313 function buy (address _idCollection, uint256 _idNFT ) public payable returns (bool result) { //buing for UNQ like as ethers 298 public314 299 payable300 returns (bool result)301 {302 //buing for UNQ like as ethers303304 Order memory order = orders[asks[_idCollection][_idNFT]];315 Order memory order = orders[asks[_idCollection][_idNFT]]; 305 //1. check sent amount and send to seller316 //1. check sent amount and send to seller326 );327 }327 }328328329 /*329/* 330 function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants330 function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants331332 Order memory order = orders[ asks[_idCollection][_idNFT]];331 332 Order memory order = orders[ asks[_idCollection][_idNFT]];333 //1. check sent amount and transfer from buyer to seller333 //1. check sent amount and transfer from buyer to seller334 require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" );334 require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" );335 // !!! transfer have to be approved to marketplace!335 // !!! transfer have to be approved to marketplace!336 IERC20(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address336 UniqueFungible(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address 337 IERC20(order.currencyCode).transfer(order.ownerAddr, order.price);337 UniqueFungible(order.currencyCode).transfer(order.ownerAddr, order.price);338 // 2. close order338 // 2. close order339 orders[ asks[_idCollection][_idNFT]].flagActive = 0;339 orders[ asks[_idCollection][_idNFT]].flagActive = 0;340 // 3. transfer NFT to buyer340 // 3. transfer NFT to buyer341 IERC721ext(_idCollection).transferFrom(address(this), msg.sender, _idNFT);341 UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);342342343343344 }344 }345 */345 */346346347 function withdrawAllKSM(address _sender)347 function withdrawAllKSM (address _sender) public nonReentrant returns (uint lastBalance ){348 public348 require(isEscrow[msg.sender] || msg.sender == _sender, "Only escrow or balance owner can withdraw all KSM" );349 onlyEscrow349350 returns (uint256 lastBalance)351 {352 lastBalance = balanceKSM[_sender];350 lastBalance = balanceKSM[_sender];353 balanceKSM[_sender] = 0;351 balanceKSM[_sender] =0;354 emit WithdrawnAllKSM(_sender, lastBalance);352 emit WithdrawnAllKSM(_sender, lastBalance);355 }353 }354355 function withdrawKSM (uint _amount, address _sender) onlyEscrow public {356 balanceKSM[_sender] = balanceKSM[_sender] - _amount;357 emit WithdrawnKSM(_sender, balanceKSM[_sender]);358 359 }356360357 function withdraw(361 function withdraw (uint256 _amount, address _currencyCode) public nonReentrant returns (bool result ){ //onlyOwner358 uint256 _amount,362 address payable _sender = payable( msg.sender);359 address _currencyCode,360 address payable _sender361 ) public onlyOwner returns (bool result) {362 if (_currencyCode != nativecoin) {363 if (_currencyCode != nativecoin ) { //erc20 compat. tokens on UNIQUE chain363 //erc20 compat. tokens on UNIQUE chain364 // uint balance = IERC20(_currencyCode).balanceOf(address(this));364 // uint balance = UniqueFungible(_currencyCode).balanceOf(address(this));365 UniqueFungible(_currencyCode).transfer(_sender, _amount);365 UniqueFungible(_currencyCode).transfer(_sender, _amount);366 } else {366 } else {367 // uint balance = address(this).balance;367 // uint balance = address(this).balance;368368369 result = (_sender).send(_amount); // for UNQ like as ethers369 result = (_sender).send(_amount); // for UNQ like as ethers 370 }370 }371 emit Withdrawn(_amount, _currencyCode, _sender);371 emit Withdrawn(_amount, _currencyCode, _sender);372 return result;372 return result;378 view379 returns (Order memory)380 {381 uint256 orderId = asks[_idCollection][_idNFT];379 uint orderId = asks[_idCollection][_idNFT];382 Order memory order = orders[orderId];380 Order memory order = orders[orderId];383 // emit GettedOrder (orderId, order);381 // emit GettedOrder (orderId, order);384 return order;382 return order;385 }383 }386384387 function getOrdersLen() public view returns (uint256) {385 function getOrdersLen () public view returns (uint) {388 return orders.length;386 return orders.length;389 }387 }388389 function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) public pure returns(bytes4) {390 return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));391 }392 393 //TODO make destructing function to return all 394 function terminate(address[] calldata tokens, NFT[] calldata nfts) public onlyOwner {395 // Transfer tokens to owner (TODO: error handling)396 for (uint i = 0; i < tokens.length; i++) {397 address addr = tokens[i];398 UniqueFungible token = UniqueFungible(addr);399 uint256 balance = token.balanceOf(address(this));400 token.transfer(owner, balance);401 }402 for (uint i = 0; i < nfts.length; i++) {403 address addr = nfts[i].collection;404 UniqueNFT token = UniqueNFT(addr);405 token.transferFrom(address(this), owner, nfts[i].id);406 } 407 // Transfer Eth to owner and terminate contract408 address payable owner1 = payable (owner);409 uint balance = address(this).balance;410 owner1.transfer(balance);411 412 } 413 390}414}391415tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth46 });46 });474748 itEth('With UNQ', async ({helper}) => {48 itEth('With UNQ', async ({helper}) => {49 const web3 = helper.getWeb3();50 const matcherOwner = await helper.eth.createAccountWithBalance(donor);49 const matcherOwner = await helper.eth.createAccountWithBalance(donor);51 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {50 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);52 from: matcherOwner,53 gas: helper.eth.DEFAULT_GAS,54 });55 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});565157 const sponsor = await helper.eth.createAccountWithBalance(donor);52 const sponsor = await helper.eth.createAccountWithBalance(donor);58 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);53 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);103 });98 });10499105 itEth('With escrow', async ({helper}) => {100 itEth('With escrow', async ({helper}) => {106 const web3 = helper.getWeb3();107 const matcherOwner = await helper.eth.createAccountWithBalance(donor);101 const matcherOwner = await helper.eth.createAccountWithBalance(donor);108 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {102 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);109 from: matcherOwner,110 gas: helper.eth.DEFAULT_GAS,111 });112 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});113103114 const sponsor = await helper.eth.createAccountWithBalance(donor);104 const sponsor = await helper.eth.createAccountWithBalance(donor);115 const escrow = await helper.eth.createAccountWithBalance(donor);105 const escrow = await helper.eth.createAccountWithBalance(donor);116 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});106 await matcher.methods.setEscrow(escrow, true).send({from: matcherOwner});117 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);107 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);118 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});108 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});119 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});109 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});172 });162 });173163174 itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {164 itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {175 const web3 = helper.getWeb3();176 const matcherOwner = await helper.eth.createAccountWithBalance(donor);165 const matcherOwner = await helper.eth.createAccountWithBalance(donor);177 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {166 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);178 from: matcherOwner,179 gas: helper.eth.DEFAULT_GAS,180 });181 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});182167183 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);168 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);184169tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth79 };79 };80 }80 }818182 async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[]): Promise<Contract> {82 async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number): Promise<Contract> {83 const compiledContract = await this.compile(name, src, imports);83 const compiledContract = await this.compile(name, src, imports);84 return this.deployByAbi(signer, compiledContract.abi, compiledContract.object);84 return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas);85 }85 }868687 async deployByAbi(signer: string, abi: any, object: string): Promise<Contract> {87 async deployByAbi(signer: string, abi: any, object: string, gas?: number): Promise<Contract> {88 const web3 = this.helper.getWeb3();88 const web3 = this.helper.getWeb3();89 const contract = new web3.eth.Contract(abi, undefined, {89 const contract = new web3.eth.Contract(abi, undefined, {90 data: object,90 data: object,91 from: signer,91 from: signer,92 gas: this.helper.eth.DEFAULT_GAS,92 gas: gas ?? this.helper.eth.DEFAULT_GAS,93 });93 });94 return await contract.deploy({data: object}).send({from: signer});94 return await contract.deploy({data: object}).send({from: signer});95 }95 }