git.delta.rocks / unique-network / refs/commits / 7a0df1a2d7c5

difftreelog

MarketPlace.sol from unique-marketplace

Andrey2022-11-10parent: #7bd00bb.patch.diff
in: master

5 files changed

deletedtests/src/eth/marketplace/MarketPlace.abidiffbeforeafterboth

no changes

deletedtests/src/eth/marketplace/MarketPlace.bindiffbeforeafterboth

no changes

modifiedtests/src/eth/marketplace/MarketPlace.soldiffbeforeafterboth
1// SPDX-License-Identifier: Apache License1// SPDX-License-Identifier: Apache License
2pragma solidity >=0.8.0;2pragma solidity >=0.8.0;
3import "../api/UniqueNFT.sol";3import {UniqueNFT, Dummy, ERC165} from "../api/UniqueNFT.sol";
44
5// Inline5// Inline
6interface 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] => idorder
71 mapping (address => mapping (uint => uint[])) public ordersbyNFT; // [addressCollection] =>idNFT =>idorder
7072
71 mapping(address => uint256[]) public asksbySeller; // [addressSeller] =>idorder73 mapping (address => uint[]) public asksbySeller; // [addressSeller] =>idorder
7274
73 address escrow;75 mapping (address =>bool) internal isEscrow;
76
77 //address escrow;
74 address owner;78 address owner;
75 address nativecoin;79 address nativecoin;
7680
77 constructor(address _escrow) {81 // from abstract contract ReentrancyGuard
82 // Booleans are more expensive than uint256 or any type that takes up a full
83 // word because each write operation emits an extra SLOAD to first read the
84 // slot's contents, replace the bits taken up by the boolean, and then write
85 // back. This is the compiler's defense against contract upgrades and
86 // pointer aliasing, and it cannot be disabled.
87
88 // 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 in
90 // amount. Since refunds are capped to a percentage of the total
91 // transaction's gas, it is best to keep them low in cases like this one, to
92 // 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;
95
96 uint8 private _status;
97
98 struct NFT {
99 address collection;
100 uint256 id;
101 }
102
103 //function initialize() public initializer {
104 constructor () { // call setEscrow directly
79 owner = msg.sender;105 owner = msg.sender;
80106
81 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 }
85
86 function setowner(address _newEscrow) public onlyOwner {
87 escrow = _newEscrow;115 _status = _NOT_ENTERED;
88 }116
89117 }
118
119 modifier nonReentrant() { // from abstract contract ReentrancyGuard
120 // On the first call to nonReentrant, _notEntered will be true
90 function setEscrow(address _newEscrow) public onlyOwner {121 require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
91 escrow = _newEscrow;122
92 }123 // Any calls to nonReentrant after this point will fail
93124 _status = _ENTERED;
94 function setNativeCoin(address _coin) public onlyOwner {125
126 _;
127
128 // By storing the original value once again, a refund is triggered (see
129 // https://eips.ethereum.org/EIPS/eip-2200)
95 nativecoin = _coin;130 _status = _NOT_ENTERED;
96 }131 }
97132
98 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 }
102137
105 _;140 _;
106 }141 }
107142
108 /**143 /**
109 * Make bids (orders) to sell NFTs144 * Make bids (orders) to sell NFTs
110 */145 */
111146
147
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 }
117
118 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 );
137167
138 event CanceledAsk(address _idCollection, uint256 _idNFT, uint256 orderId);168 event CanceledAsk (address _idCollection,
169 uint256 _idNFT,
170 uint orderId
171 );
139172
140 event DepositedKSM(uint256 _amount, address _sender);173 event DepositedKSM (uint256 _amount, address _sender);
141174
142 event BoughtNFT4KSM(175 event BoughtNFT4KSM (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
143 address _idCollection,
144 uint256 _idNFT,
145 uint256 orderID,
146 uint256 orderPrice
147 );
148176
149 event BoughtNFT(177 event BoughtNFT (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
150 address _idCollection,
151 uint256 _idNFT,
152 uint256 orderID,
153 uint256 orderPrice
154 );
155178
156 event WithdrawnAllKSM(address _sender, uint256 balance);179 event WithdrawnAllKSM (address _sender, uint256 balance);
180
181 event WithdrawnKSM (address _sender, uint256 balance);
157182
158 event Withdrawn(uint256 _amount, address _currencyCode, address _sender);183 event Withdrawn (uint256 _amount, address _currencyCode, address _sender);
184
185
186 function setOwner (address _newOwner) public onlyOwner {
187 owner = _newOwner;
188 }
189
190 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 }
197
198 function setNativeCoin (address _coin) public onlyOwner {
199 nativecoin = _coin;
200 }
201
159202
160 function addAsk(203 function addAsk (uint256 _price,
201 )242 ));
202 );243
203
204 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
257
222 uint256 orderID = asks[_idCollection][_idNFT];258 uint orderID = asks[_idCollection][_idNFT];
223259
224 require(260 require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
225 orders[orderID].ownerAddr == msg.sender,
278 uint256 _idNFT
279 ) public {
280
251 uint256 orderID = asks[_idCollection][_idNFT];281 uint orderID = asks[_idCollection][_idNFT];
252282
253 require(283 require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
254 orders[orderID].ownerAddr == msg.sender,
278 address _receiver
279 ) 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 balance
303
283 balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;304 balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;
294 );
295 }312 }
296
297 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 payable
300 returns (bool result)
301 {
302 //buing for UNQ like as ethers
303
304 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 seller
326 );
327 }327 }
328328
329 /*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 wants
331
332 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 seller
334 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 order
339 orders[ asks[_idCollection][_idNFT]].flagActive = 0;339 orders[ asks[_idCollection][_idNFT]].flagActive = 0;
340 // 3. transfer NFT to buyer340 // 3. transfer NFT to buyer
341 IERC721ext(_idCollection).transferFrom(address(this), msg.sender, _idNFT);341 UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);
342342
343343
344 }344 }
345 */345 */
346346
347 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 onlyEscrow349
350 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 }
354
355 function withdrawKSM (uint _amount, address _sender) onlyEscrow public {
356 balanceKSM[_sender] = balanceKSM[_sender] - _amount;
357 emit WithdrawnKSM(_sender, balanceKSM[_sender]);
358
359 }
356360
357 function withdraw(361 function withdraw (uint256 _amount, address _currencyCode) public nonReentrant returns (bool result ){ //onlyOwner
358 uint256 _amount,362 address payable _sender = payable( msg.sender);
359 address _currencyCode,
360 address payable _sender
361 ) public onlyOwner returns (bool result) {
362 if (_currencyCode != nativecoin) {363 if (_currencyCode != nativecoin ) { //erc20 compat. tokens on UNIQUE chain
363 //erc20 compat. tokens on UNIQUE chain
364 // 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;
368368
369 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 view
379 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 }
386384
387 function getOrdersLen() public view returns (uint256) {385 function getOrdersLen () public view returns (uint) {
388 return orders.length;386 return orders.length;
389 }387 }
388
389 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 contract
408 address payable owner1 = payable (owner);
409 uint balance = address(this).balance;
410 owner1.transfer(balance);
411
412 }
413
390}414}
391415
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
46 });46 });
4747
48 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});
5651
57 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 });
10499
105 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});
113103
114 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 });
173163
174 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});
182167
183 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);168 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);
184169
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
79 };79 };
80 }80 }
8181
82 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 }
8686
87 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 }