Giter Site home page Giter Site logo

wyvernprotocol / wyvern-v3 Goto Github PK

View Code? Open in Web Editor NEW
301.0 18.0 122.0 4.98 MB

Wyvern Protocol v3.1, Ethereum implementation

Home Page: https://wyvernprotocol.com

License: MIT License

Shell 0.87% JavaScript 58.13% Solidity 41.00%
ethereum dex nft wyvern

wyvern-v3's Introduction

Wyvern v3.1

Project Wyvern Logo

https://img.shields.io/github/license/wyvernprotocol/wyvern-v3.svg Build Status Coverage Status

This is version 3.1 of the Wyvern decentralized exchange protocol, designed to maximize the ease of positive-utility-sum multiparty transactions on a distributed ledger.

Check out documentation here.

Deployed contract addresses can be found in config.json.

Development

Setup

Install dependencies with Yarn:

yarn

Testing

Run testrpc (ganache-cli) to provide a simulated EVM:

yarn testrpc

In a separate terminal, run the testuite:

yarn test

Linting

Lint all Solidity files with:

yarn lint

Static Analysis

Run static analysis tooling with:

yarn analyze

Deployment

Edit truffle.js according to your deployment plans, then run:

yarn run truffle deploy --network [network]

wyvern-v3's People

Contributors

alexanderatallah avatar cwgoes avatar dependabot[bot] avatar itsmarcosolis avatar jackcpku avatar marvinjanssen avatar rotcivegaf avatar smlaursen avatar stewart-lore avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wyvern-v3's Issues

How about use `WyvernAtomicizer.atomicize` for eth transfer?

Ok, for anyone interested in how this worked out in the end, below is a sample code that works. However, it involves a new predicate transferERC20ExactTo which gets the fee recipient via the extra data.

Click for code
it("erc721 <> erc20 with checks", async () => {
    const alice = accounts[0];
    const bob = accounts[1];
    const carol = accounts[2];
    const david = accounts[3];

    const { atomicizer, exchange, registry, statici } =
      await deployCoreContracts();
    const [erc20, erc721] = await deploy([TestERC20, TestERC721]);

    const abi = [
      {
        constant: false,
        inputs: [
          { name: "addrs", type: "address[]" },
          { name: "values", type: "uint256[]" },
          { name: "calldataLengths", type: "uint256[]" },
          { name: "calldatas", type: "bytes" },
        ],
        name: "atomicize",
        outputs: [],
        payable: false,
        stateMutability: "nonpayable",
        type: "function",
      },
    ];
    const atomicizerc = new web3.eth.Contract(abi, atomicizer.address);

    await registry.registerProxy({ from: alice });
    const aliceProxy = await registry.proxies(alice);
    assert.equal(true, aliceProxy.length > 0, "No proxy address for Alice");

    await registry.registerProxy({ from: bob });
    const bobProxy = await registry.proxies(bob);
    assert.equal(true, bobProxy.length > 0, "No proxy address for Bob");

    const amount = 1000;
    const fee1 = 10;
    const fee2 = 20;
    const tokenId = 0;

    await Promise.all([
      erc20.mint(bob, amount + fee1 + fee2),
      erc721.mint(alice, tokenId),
    ]);

    await Promise.all([
      erc20.approve(bobProxy, amount + fee1 + fee2, { from: bob }),
      erc721.setApprovalForAll(aliceProxy, true, { from: alice }),
    ]);

    const erc20c = new web3.eth.Contract(erc20.abi, erc20.address);
    const erc721c = new web3.eth.Contract(erc721.abi, erc721.address);

    let selectorOne, extradataOne;
    {
      const selector = web3.eth.abi.encodeFunctionSignature(
        "split(bytes,address[7],uint8[2],uint256[6],bytes,bytes)"
      );
      // Call should be an ERC721 transfer
      const selectorCall = web3.eth.abi.encodeFunctionSignature(
        "transferERC721Exact(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const extradataCall = web3.eth.abi.encodeParameters(
        ["address", "uint256"],
        [erc721.address, tokenId]
      );
      // Countercall should include an ERC20 transfer
      const selectorCountercall = web3.eth.abi.encodeFunctionSignature(
        "sequenceAnyAfter(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const countercallSelector1 = web3.eth.abi.encodeFunctionSignature(
        "transferERC20Exact(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const countercallExtradata1 = web3.eth.abi.encodeParameters(
        ["address", "uint256"],
        [erc20.address, amount]
      );
      const extradataCountercall = web3.eth.abi.encodeParameters(
        ["address[]", "uint256[]", "bytes4[]", "bytes"],
        [
          [statici.address],
          [(countercallExtradata1.length - 2) / 2],
          [countercallSelector1],
          countercallExtradata1,
        ]
      );

      const params = web3.eth.abi.encodeParameters(
        ["address[2]", "bytes4[2]", "bytes", "bytes"],
        [
          [statici.address, statici.address],
          [selectorCall, selectorCountercall],
          extradataCall,
          extradataCountercall,
        ]
      );

      selectorOne = selector;
      extradataOne = params;
    }

    const one = {
      registry: registry.address,
      maker: alice,
      staticTarget: statici.address,
      staticSelector: selectorOne,
      staticExtradata: extradataOne,
      maximumFill: 1,
      listingTime: "0",
      expirationTime: "10000000000",
      salt: "11",
    };
    const sigOne = await exchange.sign(one, alice);

    let selectorTwo, extradataTwo;
    {
      const selector = web3.eth.abi.encodeFunctionSignature(
        "split(bytes,address[7],uint8[2],uint256[6],bytes,bytes)"
      );
      // Call should be an ERC20 transfer to recipient + fees
      const selectorCall = web3.eth.abi.encodeFunctionSignature(
        "sequenceExact(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const callSelector1 = web3.eth.abi.encodeFunctionSignature(
        "transferERC20Exact(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const callExtradata1 = web3.eth.abi.encodeParameters(
        ["address", "uint256"],
        [erc20.address, amount]
      );
      const callSelector2 = web3.eth.abi.encodeFunctionSignature(
        "transferERC20ExactTo(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const callExtradata2 = web3.eth.abi.encodeParameters(
        ["address", "uint256", "address"],
        [erc20.address, fee1, carol]
      );
      const callSelector3 = web3.eth.abi.encodeFunctionSignature(
        "transferERC20ExactTo(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const callExtradata3 = web3.eth.abi.encodeParameters(
        ["address", "uint256", "address"],
        [erc20.address, fee2, david]
      );
      const extradataCall = web3.eth.abi.encodeParameters(
        ["address[]", "uint256[]", "bytes4[]", "bytes"],
        [
          [statici.address, statici.address, statici.address],
          [
            (callExtradata1.length - 2) / 2,
            (callExtradata2.length - 2) / 2,
            (callExtradata3.length - 2) / 2,
          ],
          [callSelector1, callSelector2, callSelector3],
          callExtradata1 +
            callExtradata2.slice("2") +
            callExtradata3.slice("2"),
        ]
      );
      // Countercall should be an ERC721 transfer
      const selectorCountercall = web3.eth.abi.encodeFunctionSignature(
        "transferERC721Exact(bytes,address[7],uint8,uint256[6],bytes)"
      );
      const extradataCountercall = web3.eth.abi.encodeParameters(
        ["address", "uint256"],
        [erc721.address, tokenId]
      );

      const params = web3.eth.abi.encodeParameters(
        ["address[2]", "bytes4[2]", "bytes", "bytes"],
        [
          [statici.address, statici.address],
          [selectorCall, selectorCountercall],
          extradataCall,
          extradataCountercall,
        ]
      );

      selectorTwo = selector;
      extradataTwo = params;
    }

    const two = {
      registry: registry.address,
      maker: bob,
      staticTarget: statici.address,
      staticSelector: selectorTwo,
      staticExtradata: extradataTwo,
      maximumFill: amount,
      listingTime: "0",
      expirationTime: "10000000000",
      salt: "12",
    };
    const sigTwo = await exchange.sign(two, bob);

    const firstData = erc721c.methods
      .transferFrom(alice, bob, tokenId)
      .encodeABI();

    const c1 = erc20c.methods.transferFrom(bob, alice, amount).encodeABI();
    const c2 = erc20c.methods.transferFrom(bob, carol, fee1).encodeABI();
    const c3 = erc20c.methods.transferFrom(bob, david, fee2).encodeABI();
    const secondData = atomicizerc.methods
      .atomicize(
        [erc20.address, erc20.address, erc20.address],
        [0, 0, 0],
        [(c1.length - 2) / 2, (c2.length - 2) / 2, (c3.length - 2) / 2],
        c1 + c2.slice("2") + c3.slice("2")
      )
      .encodeABI();

    const firstCall = { target: erc721.address, howToCall: 0, data: firstData };
    const secondCall = {
      target: atomicizer.address,
      howToCall: 1,
      data: secondData,
    };

    await exchange.atomicMatchWith(
      one,
      sigOne,
      firstCall,
      two,
      sigTwo,
      secondCall,
      ZERO_BYTES32,
      { from: carol }
    );

    const [
      aliceErc20Balance,
      carolErc20Balance,
      davidErc20Balance,
      tokenIdOwner,
    ] = await Promise.all([
      erc20.balanceOf(alice),
      erc20.balanceOf(carol),
      erc20.balanceOf(david),
      erc721.ownerOf(tokenId),
    ]);
    assert.equal(
      aliceErc20Balance.toNumber(),
      amount,
      "Incorrect ERC20 balance"
    );
    assert.equal(carolErc20Balance.toNumber(), fee1, "Incorrect ERC20 balance");
    assert.equal(davidErc20Balance.toNumber(), fee2, "Incorrect ERC20 balance");
    assert.equal(tokenIdOwner, bob, "Incorrect token owner");
  });

Originally posted by @georgeroman in #56 (comment)

Integration with a marketplace

hello, I'm developing a new nft marketplace where users can sell and buy NFT.
In the current version, my smartcontract transfers NFT from buyer to seller and erc20 tokens from seller to buyer. No auctions, just a buy now, so after click the exchange is done. Everything works fine, but I dont understand if I need mandatory to use wyvern (and how) in order for my trade to be listed on opensea in example or on nft-stats.com.
Thank you

test failed in 5-wyvern-exchange-matching.js

I got a same problem in some cases when running the 5-wyvern-exchange-matching.js, such as 'does not match any-any reentrant order'. As shown in the picture below(I run the test in truffle develop):
image
Transaction: 0xfd1355c906114edcf3929a0945279916ed0ada7c3df58d7e09f2865216028478 exited with an error (status 0) after consuming all gas.
Please check that the transaction:
- satisfies all conditions set by Solidity assert statements.
- has enough gas to execute the full transaction.
- does not trigger an invalid opcode by other means (ex: accessing an array out of bounds).
Then I debuged this transaction and found that the transaction failed with the function executeCall in ExchangeCore.sol 'require(executeCall(ProxyRegistryInterface(firstOrder.registry), firstOrder.maker, firstCall), "First call failed");'.
Why did the firstcall go wrong and not the secondcall๏ผŸ
What gets even weirder is that if I replace the secondCall with firstCall(Only replace the params in test not in contract), it works well. As shown in the picture below(replace the call2 with call1, it works well):
image
I also got the same problem in other test cases, including 'matches nft-nft swap order', 'matches nft-nft swap order, abi-decoding instead' and 'matches erc20-erc20 swap order'

Cannot Deploy to Rinkeby

I followed README.

  1. yarn install
  2. yarn run truffle deploy --network deployment
  3. Updated truffle.js with my mnemonic and infura URI.
  4. yarn run truffle deploy --network rinkeby

Fails on WyvernExchange contract with rinkeby-fork.

I'm having a heck of a time trying to debug this. I deleted node_modules and reinstalled via yarn. I verified my truffle versions are correct:

Truffle v5.2.3 (core: 5.2.3)
Solidity - 0.7.5 (solc-js)
Node v15.12.0
Web3.js v1.2.9

I'm lost and dont know where to get help from.

   > account:             0xd954F4513BdE1E00F3986630A7e73c4f9aA564fE
   > balance:             12.6811270689
   > gas used:            2147921 (0x20c651)
   > gas price:           21.11 gwei
   > value sent:          0 ETH
   > total cost:          0.04534261231 ETH


   Deploying 'WyvernExchange'
   --------------------------

Error:  *** Deployment Failed ***

"WyvernExchange" -- Cannot read property 'length' of undefined.

    at /Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:365:1
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at Migration._deploy (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:68:1)
    at Migration._load (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:55:1)
    at Migration.run (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:171:1)
    at Object.runMigrations (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/index.js:150:1)
    at Object.runFrom (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/index.js:110:1)
    at Object.run (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/migrate/index.js:87:1)
    at runMigrations (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:269:1)
    at setupDryRunEnvironmentThenRunMigrations (/Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:257:1)
    at /Users/stevers/Projects/Cryptocurrency/ethereum/wyvern-v3/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:220:1
Truffle v5.1.55 (core: 5.1.55)
Node v15.12.0

What is the relation to the original ProjectWyvern

I didn't find anything official on the history of project wyvern.

Is this repository an official continuation of the original https://github.com/ProjectWyvern/wyvern-ethereum made by the same team? Or is it an independent fork?

It seems that the original stopped being maintained somewhere in 2018 and I can't find anything from the lead developer(?) @protinam after that.

Who is maintaining the websites https://projectwyvern.com and https://wyvernprotocol.com?

Also what is the relation to opensea? They recently released version 2.3 of their copy(?) of the wyvern exchange.

I also found some invites to an official discord channel, but they are all expired, is that channel still alive?

Transfer relayer fee for anyERC20ForERC1155

Hi, I go through the tests in "7-static-market-matching.js" to exchange ERC1155 and ERC20 with anyERC1155ForERC20 and anyERC20ForERC1155

Wonder if it is possible to transfer ERC20 to 2 addresses, one for ERC1155 owner and another for a relayer, in second call

It would be appreciated if someone could help on it.

Thanks a lot.

Integrating fees

Hello everyone! I'm looking into integrating fees within the orders. That is, the maker of an order involving selling an ERC20 asset is responsible for paying a list of fee recipients - these must be specified beforehand and signed by the maker so that they're enforced on-chain. I'm having a hard time composing the proper predicates for this. Are there any concrete examples of this?

Optional User's Proxy for the atomicMatch

From what i understood, in order to do any exchange (atomicMatch) the taker & maker (buyer & seller) must have the proxy registered in the ProxyRegistry.

In the case of doing NFT ERC20 trade, we might not require the buyer (the one who will send erc20) to have the proxy & do the approval of ERC20 to the proxy. Instead, we might just use the tokenTransferProxy and then only approve the ERC20 to that tokenTransferProxy (similar like what in wyvern v2 did), so the buyer doesn't require to register the proxy first which causes additional gas fee.

Is there any workaround how to solve this issue?

Examples to integrate with Wyvern from a smart contract

Hello there,

Thanks for the amazing platform! We're building a NFT platform with some special rules, because of these (specifically that "transferFrom" and "approve" cannot be called by owners themselves) we have to automatically list them on OpenSea.

From my understanding so far we need to call approveOrder_ from a contract who has the ability to do approve and transferFrom on those NFTs. We were thinking of having a "Marketer" contract which has a special access to do these operations on all NFTs on behalf of holders.

Assuming, above is correct there are a few questions I have:

  1. Do we need to have a proxy for this Marketer contract of ours? e.g. to call "registerProxy" on its constructor. If yes is it possible to implement required capabilities within our Marketer contract so we can avoid having a proxy?
  2. These orders need to be using ETH (and WETH maybe?) in terms of being asymmetrical, is it possible to do what we want to achieve? i.e. To put the NFT for sale on automatically behalf of holder for a certain price, and have it automatically show up on OpenSea?
  3. Is there any "solidity" examples available where a smart contract calls Wyvern exchange, there are some javascript examples but mapping them to solidity is a bit tricky.

Thank you so much in advance :)

Consider splitting concerns of static calls

General concern about calls happening before static checks.

  • Authenticate call data
  • Return fill
  • Check state changes
  • Call gets signed? Maybe an option.

Other points

  • If maker == sender, do we need a static call at all? Then we could avoid anyXYZ contracts.
  • Orders could optionally sign some hash of calldata
  • Maybe an application-operator-specific whitelist (application operator could change)

Global proxy with secondary order authentication

Goal is to allow easy transferFrom usage without deployment of a second proxy.

  • Exchange contract requires known AuthenticatedProxy implementation for semantic correctness of proxy
    • Could add an extra, specially authorised, revised contract which has logic to check transferFrom signatures
    • Need to pass additional data to the proxy contract so that it can authenticate signatures
  • Alternative approach: make order maker a contract
    • Use the same proxy contract
    • isValidSignature-equivalent method checks signature on behalf of user
      • Basically checks that the user (looked up from call data) signed the Wyvern order
      • Is there an altered version of EIP 1271 that allows passing extra data?
    • Needs to pass call data as well so user can be looked up
    • Can choose to require additional signature (e.g. by relayer) or not
    • Users then approve proxy deployed by this contract

Add order & settlement examples, testcases

Including comprehensive static callback examples for:

  • Orders behaving the same as v2 orders (since v3 is a strict superset)
  • Fixed-price and auction pricing
  • Orders which utilize new maximally gas-efficient static callback style
  • n-for-m NFT trades

The order examples can also be used as test vectors.

how to call WyvernExchangeContract to mumbai

mumbai node: https://rpc-mumbai.maticvigil.com/v1/mykey

self.web3ContractInstance.validateOrderParameters_.call(addrs_0[0], addrs_0[1], addrs_0[5], '0x00000000', '0x', 1, 0, 1000000000000, 0)

call result:

(node:4173) UnhandledPromiseRejectionWarning: Error: execution reverted
at Object.InvalidResponse (/usr/nft/openlake-js/node_modules/wyvern-js/node_modules/[email protected]@web3/lib/web3/errors.js:38:16)
at /usr/nft/openlake-js/node_modules/wyvern-js/node_modules/[email protected]@web3/lib/web3/requestmanager.js:86:36
at XMLHttpRequest.request.onreadystatechange (/usr/nft/openlake-js/node_modules/[email protected]@web3/lib/web3/httpprovider.js:129:7)
at XMLHttpRequestEventTarget.dispatchEvent (/usr/nft/openlake-js/node_modules/_xhr2-cookies@1.1.0@xhr2-cookies/dist/xml-http-request-event-target.js:34:22)
at XMLHttpRequest._setReadyState (/usr/nft/openlake-js/node_modules/_xhr2-cookies@1.1.0@xhr2-cookies/dist/xml-http-request.js:208:14)
at XMLHttpRequest._onHttpResponseEnd (/usr/nft/openlake-js/node_modules/_xhr2-cookies@1.1.0@xhr2-cookies/dist/xml-http-request.js:318:14)
at IncomingMessage. (/usr/nft/openlake-js/node_modules/_xhr2-cookies@1.1.0@xhr2-cookies/dist/xml-http-request.js:289:61)
at IncomingMessage.emit (events.js:215:7)
at endReadableNT (_stream_readable.js:1198:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)

anyone know how to solve this problem?

Incorrect implementation of EIP-1271

You are not using the latest implementation of EIP-1271 which uses function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue); hence contracts implementing the correct version will return a different magic value (0x1626ba7e) and the check will fail, see https://eips.ethereum.org/EIPS/eip-1271.

abstract contract ERC1271 {
and
bytes4 constant internal EIP_1271_MAGICVALUE = 0x20c13b0b;
should be updated.

Bug report for StaticMarket.sol

function ERC20ForERC721(bytes memory extra,
address[7] memory addresses, AuthenticatedProxy.HowToCall[2] memory howToCalls, uint[6] memory uints,
bytes memory data, bytes memory counterdata)
public
pure
returns (uint)
{
require(uints[0] == 0,"ERC20ForERC721: Zero value required");
require(howToCalls[0] == AuthenticatedProxy.HowToCall.Call, "ERC20ForERC721: call must be a direct call");
(address[2] memory tokenGiveGet, uint256[2] memory tokenIdAndPrice) = abi.decode(extra, (address[2], uint256[2]));
require(tokenIdAndPrice[1] > 0,"ERC20ForERC721: ERC721 price must be larger than zero");
require(addresses[2] == tokenGiveGet[0], "ERC20ForERC721: call target must equal address of token to give");
require(addresses[5] == tokenGiveGet[1], "ERC20ForERC721: countercall target must equal address of token to get");
checkERC721Side(counterdata,addresses[4],addresses[1],tokenIdAndPrice[0]);
checkERC20Side(data,addresses[1],addresses[4],tokenIdAndPrice[1]);
return 1;
}

The return value should not be 1 since multiple ERC20 tokens are transferred. This will cause inconsistency with the meaning of variable fills.

Examples?

I can't find any example code in the docs. Would be nice to at least see an example implementation somewhere. Really hard to determine what I'm supposed to pass into atomicMatch by just looking at the code.

Error on initial migration

Error: CompileError: /Users/x/Documents/webs/wyvern-v3/contracts/exchange/Exchange.sol:77:27: CompilerError: Stack too deep, try removing local variables.
Order(address(uints[0]), address(uints[1]), address(ui ...
^---^

Compilation failed. See above.
at Object.compile (/usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-workflow-compile/index.js:103:1)
Truffle v5.0.29 (core: 5.0.29)
Node v10.16.0

Having issues with ExchangeCore code

Hi all!

I'm currently studying the contracts in order to build on top of wyvern later on. But now I'm having trouble understanding the code. In the following function:

function atomicMatch(Order memory firstOrder, Call memory firstCall, Order memory secondOrder, Call memory secondCall, bytes memory signatures, bytes32 metadata)
internal
reentrancyGuard
{
/* CHECKS */
/* Calculate first order hash. */
bytes32 firstHash = hashOrder(firstOrder);
/* Check first order validity. */
require(validateOrderParameters(firstOrder, firstHash), "First order has invalid parameters");
/* Calculate second order hash. */
bytes32 secondHash = hashOrder(secondOrder);
/* Check second order validity. */
require(validateOrderParameters(secondOrder, secondHash), "Second order has invalid parameters");
/* Prevent self-matching (possibly unnecessary, but safer). */
require(firstHash != secondHash, "Self-matching orders is prohibited");
{
/* Calculate signatures (must be awkwardly decoded here due to stack size constraints). */
(bytes memory firstSignature, bytes memory secondSignature) = abi.decode(signatures, (bytes, bytes));
/* Check first order authorization. */
require(validateOrderAuthorization(firstHash, firstOrder.maker, firstSignature), "First order failed authorization");
/* Check second order authorization. */
require(validateOrderAuthorization(secondHash, secondOrder.maker, secondSignature), "Second order failed authorization");
}
/* INTERACTIONS */
/* Transfer any msg.value.
This is the first "asymmetric" part of order matching: if an order requires Ether, it must be the first order. */
if (msg.value > 0) {
address(uint160(firstOrder.maker)).transfer(msg.value);
}
/* Execute first call, assert success.
This is the second "asymmetric" part of order matching: execution of the second order can depend on state changes in the first order, but not vice-versa. */
require(executeCall(ProxyRegistryInterface(firstOrder.registry), firstOrder.maker, firstCall), "First call failed");
/* Execute second call, assert success. */
require(executeCall(ProxyRegistryInterface(secondOrder.registry), secondOrder.maker, secondCall), "Second call failed");
/* Static calls must happen after the effectful calls so that they can check the resulting state. */
/* Fetch previous first order fill. */
uint previousFirstFill = fills[firstOrder.maker][firstHash];
/* Fetch previous second order fill. */
uint previousSecondFill = fills[secondOrder.maker][secondHash];
/* Execute first order static call, assert success, capture returned new fill. */
uint firstFill = executeStaticCall(firstOrder, firstCall, secondOrder, secondCall, msg.sender, msg.value, previousFirstFill);
/* Execute second order static call, assert success, capture returned new fill. */
uint secondFill = executeStaticCall(secondOrder, secondCall, firstOrder, firstCall, msg.sender, uint(0), previousSecondFill);
/* EFFECTS */
/* Update first order fill, if necessary. */
if (firstOrder.maker != msg.sender) {
if (firstFill != previousFirstFill) {
fills[firstOrder.maker][firstHash] = firstFill;
}
}
/* Update second order fill, if necessary. */
if (secondOrder.maker != msg.sender) {
if (secondFill != previousSecondFill) {
fills[secondOrder.maker][secondHash] = secondFill;
}
}
/* LOGS */
/* Log match event. */
emit OrdersMatched(firstHash, secondHash, firstOrder.maker, secondOrder.maker, firstFill, secondFill, metadata);
}

Why must the static calls be after the effectful calls? How can they "check the resulting state"? It seems to me that swapping the effectful calls and static calls makes no difference.

I also have great difficulty understanding the purpose of all the "static" things. I'll appreciate it if someone could help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.