This repository has been archived by the owner on Dec 5, 2021. It is now read-only.
forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TURING OFFCHAIN COMPUTE: add uniswapv2 fee example (incomplete) - WIP (…
…#315) * add uniswapv2 fee example (incomplete) * add offchain in uniswapv2pair * feat: update fee-test Co-authored-by: Mehul Agarwal <[email protected]> Co-authored-by: souradeep-das <[email protected]> Co-authored-by: CAPtheorem <[email protected]>
- Loading branch information
1 parent
5199db8
commit b9c2dfe
Showing
7 changed files
with
709 additions
and
99 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
omgx_examples/hardhat_ERC721/contracts/boredBobaYachtClub.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,127 @@ | ||
// File: contracts/BoredBobaYachtClub.sol | ||
|
||
|
||
pragma solidity ^0.7.0; | ||
|
||
|
||
|
||
/** | ||
* @title BoredBobaYachtClub contract | ||
* @dev Extends ERC721 Non-Fungible Token Standard basic implementation | ||
*/ | ||
contract BoredBobaYachtClub is ERC721, Ownable { | ||
using SafeMath for uint256; | ||
|
||
string public BAYC_PROVENANCE = ""; | ||
|
||
uint256 public startingIndexBlock; | ||
|
||
uint256 public startingIndex; | ||
|
||
uint256 public constant bobaPrice = 80000000000000000; //0.08 ETH | ||
|
||
uint public constant maxBobaPurchase = 20; | ||
|
||
uint256 public MAX_BOBAS; | ||
|
||
bool public saleIsActive = false; | ||
|
||
uint256 public REVEAL_TIMESTAMP; | ||
|
||
constructor(string memory name, string memory symbol, uint256 maxNftSupply, uint256 saleStart) ERC721(name, symbol) { | ||
MAX_BOBAS = maxNftSupply; | ||
REVEAL_TIMESTAMP = saleStart + (86400 * 9); | ||
} | ||
|
||
function withdraw() public onlyOwner { | ||
uint balance = address(this).balance; | ||
msg.sender.transfer(balance); | ||
} | ||
|
||
/** | ||
* Set some Bored Bobas aside | ||
*/ | ||
function reserveBobas() public onlyOwner { | ||
uint supply = totalSupply(); | ||
uint i; | ||
for (i = 0; i < 30; i++) { | ||
_safeMint(msg.sender, supply + i); | ||
} | ||
} | ||
|
||
/** | ||
* DM Gargamel in Discord that you're standing right behind him. | ||
*/ | ||
function setRevealTimestamp(uint256 revealTimeStamp) public onlyOwner { | ||
REVEAL_TIMESTAMP = revealTimeStamp; | ||
} | ||
|
||
/* | ||
* Set provenance once it's calculated | ||
*/ | ||
function setProvenanceHash(string memory provenanceHash) public onlyOwner { | ||
BAYC_PROVENANCE = provenanceHash; | ||
} | ||
|
||
function setBaseURI(string memory baseURI) public onlyOwner { | ||
_setBaseURI(baseURI); | ||
} | ||
|
||
/* | ||
* Pause sale if active, make active if paused | ||
*/ | ||
function flipSaleState() public onlyOwner { | ||
saleIsActive = !saleIsActive; | ||
} | ||
|
||
/** | ||
* Mints Bored Bobas | ||
*/ | ||
function mintBoba(uint numberOfTokens) public payable { | ||
require(saleIsActive, "Sale must be active to mint Boba"); | ||
require(numberOfTokens <= maxBobaPurchase, "Can only mint 20 tokens at a time"); | ||
require(totalSupply().add(numberOfTokens) <= MAX_BOBAS, "Purchase would exceed max supply of Bobas"); | ||
require(bobaPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct"); | ||
|
||
for(uint i = 0; i < numberOfTokens; i++) { | ||
uint mintIndex = totalSupply(); | ||
if (totalSupply() < MAX_BOBAS) { | ||
_safeMint(msg.sender, mintIndex); | ||
} | ||
} | ||
|
||
// If we haven't set the starting index and this is either 1) the last saleable token or 2) the first token to be sold after | ||
// the end of pre-sale, set the starting index block | ||
if (startingIndexBlock == 0 && (totalSupply() == MAX_BOBAS || block.timestamp >= REVEAL_TIMESTAMP)) { | ||
startingIndexBlock = block.number; | ||
} | ||
} | ||
|
||
/** | ||
* Set the starting index for the collection | ||
*/ | ||
function setStartingIndex() public { | ||
require(startingIndex == 0, "Starting index is already set"); | ||
require(startingIndexBlock != 0, "Starting index block must be set"); | ||
|
||
startingIndex = uint(blockhash(startingIndexBlock)) % MAX_BOBAS; | ||
// Just a sanity case in the worst case if this function is called late (EVM only stores last 256 block hashes) | ||
if (block.number.sub(startingIndexBlock) > 255) { | ||
startingIndex = uint(blockhash(block.number - 1)) % MAX_BOBAS; | ||
} | ||
// Prevent default sequence | ||
if (startingIndex == 0) { | ||
startingIndex = startingIndex.add(1); | ||
} | ||
} | ||
|
||
/** | ||
* Set the starting index block for the collection, essentially unblocking | ||
* setting starting index | ||
*/ | ||
function emergencySetStartingIndexBlock() public onlyOwner { | ||
require(startingIndex == 0, "Starting index is already set"); | ||
|
||
startingIndexBlock = block.number; | ||
} | ||
} |
190 changes: 190 additions & 0 deletions
190
omgx_examples/sushi/contracts/uniswapv2/TuringHelper.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,190 @@ | ||
//SPDX-License-Identifier: UNLICENSED | ||
|
||
pragma solidity ^0.7.0; | ||
|
||
import "hardhat/console.sol"; | ||
|
||
contract TuringHelper { | ||
bytes data_URL; | ||
TuringHelper Self; | ||
bytes[] methods; | ||
|
||
constructor(string memory _url) { | ||
console.log("Deploying a helper contract with data source:", _url); | ||
data_URL = bytes(_url); | ||
Self = TuringHelper(address(this)); | ||
} | ||
|
||
function RegisterMethod(bytes memory methodName) public { | ||
methods.push(methodName); | ||
} | ||
|
||
function _lenCalc1(bytes memory item, uint32 len) internal pure | ||
returns (uint8, uint32) | ||
{ | ||
uint32 L = uint32(item.length); | ||
uint8 prefix; | ||
|
||
if (L > 255) { | ||
len += 3; | ||
prefix = 0xb9; | ||
} else if (L > 55) { | ||
len += 2; | ||
prefix = 0xb8; | ||
} else { | ||
len += 1; | ||
prefix = 0x80 + uint8(L); | ||
} | ||
|
||
return (prefix, len); | ||
} | ||
|
||
function genRequestRLP(bytes memory method, bytes memory payload) internal view | ||
returns (bytes memory) | ||
{ | ||
// This function generates a Turing request consisting of a | ||
// fixed prefix string followed by parameters in RLP encoding. | ||
// The outer container is a 4-element array containing a | ||
// single-byte version number and 3 strings: URL, method, request | ||
// payload. The payload is passed as-is to the remote server, | ||
// which is responsible for unpacking and interpreting it. | ||
|
||
// For now this is the only valid value and all others are reserved. | ||
byte request_version = 0x01; | ||
|
||
bytes memory prefix = bytes("_OMGXTURING_"); | ||
assert (prefix.length == 12); | ||
uint i; | ||
uint j; | ||
|
||
// Constrain these to simplify the RLP encoding logic. | ||
require (data_URL.length < 65536, "data_URL is too long"); | ||
require (payload.length < 65536, "payload is too long"); | ||
|
||
uint32 l1 = uint32(data_URL.length); | ||
uint32 l2 = uint32(method.length); | ||
uint32 l3 = uint32(payload.length); | ||
|
||
uint32 pLen = 1 + l1 + l2 + l3; // Payload length + inner headers | ||
uint32 hLen = 1; // Extra length of list header | ||
|
||
uint8[4] memory pre; | ||
|
||
(pre[1], pLen) = _lenCalc1(data_URL, pLen); | ||
(pre[2], pLen) = _lenCalc1(method, pLen); | ||
(pre[3], pLen) = _lenCalc1(payload, pLen); | ||
|
||
// We now have the total length of the three items which will be in the list. | ||
// This determines the encoding required for the list header | ||
|
||
if (pLen > 65535) { | ||
hLen += 3; | ||
pre[0] = 0xfa; | ||
} else if (pLen > 255) { | ||
hLen += 2; | ||
pre[0] = 0xf9; | ||
} else if (pLen > 55) { | ||
hLen += 1; | ||
pre[0] = 0xf8; | ||
} else { | ||
pre[0] = 0xc0 + uint8(pLen); | ||
} | ||
|
||
bytes memory result = new bytes(hLen + pLen + prefix.length); | ||
|
||
for (i=0; i < prefix.length; i++) result[j++] = prefix[i]; | ||
|
||
result[j++] = bytes1(pre[0]); | ||
|
||
if (pre[0] > 0xf9) { | ||
result[j++] = bytes1(uint8(pLen / 65536)); | ||
pLen = pLen % 65536; | ||
} | ||
if (pre[0] > 0xf8) { | ||
result[j++] = bytes1(uint8(pLen / 256)); | ||
pLen = pLen % 256; | ||
} | ||
if (pre[0] > 0xf7) { | ||
result[j++] = bytes1(uint8(pLen)); | ||
} | ||
|
||
result[j++] = request_version; | ||
|
||
result[j++] = bytes1(pre[1]); | ||
if (pre[1] > 0xb8) { | ||
result[j++] = bytes1(uint8(l1 / 256)); | ||
l1 = l1 % 256; | ||
} | ||
if (pre[1] > 0xb7) { | ||
result[j++] = bytes1(uint8(l1)); | ||
} | ||
for (i=0; i<data_URL.length; i++) result[j++] = data_URL[i]; | ||
|
||
result[j++] = bytes1(pre[2]); | ||
if (pre[2] > 0xb8) { | ||
result[j++] = bytes1(uint8(l2 / 256)); | ||
l2 = l2 % 256; | ||
} | ||
if (pre[2] > 0xb7) { | ||
result[j++] = bytes1(uint8(l2)); | ||
} | ||
for (i=0; i<method.length; i++) result[j++] = method[i]; | ||
|
||
result[j++] = bytes1(pre[3]); | ||
if (pre[3] > 0xb8) { | ||
result[j++] = bytes1(uint8(l3 / 256)); | ||
l3 = l3 % 256; | ||
} | ||
if (pre[3] > 0xb7) { | ||
result[j++] = bytes1(uint8(l3)); | ||
} | ||
for (i=0; i<payload.length; i++) result[j++] = payload[i]; | ||
return result; | ||
} | ||
|
||
/* This is the interface to the off-chain mechanism. Although | ||
marked as "public", it is only to be called by TuringCall(). | ||
The _slot parameters is overloaded to represent either the | ||
request parameters or the off-chain response, with the rType | ||
parameter indicating which is which. When called as a request, | ||
it reverts with an encoded OMGX_TURING string. The modified | ||
l2geth intercepts this, performs the off-chain interaction, | ||
then rewrites the parameters and calls the method again in | ||
"response" mode. This response is then passed back to the | ||
caller. | ||
*/ | ||
function GetResponse(uint32 method_idx, uint32 rType, bytes memory _slot) | ||
public view returns (bytes memory) { | ||
|
||
require (msg.sender == address(this)); | ||
require (rType == 1 || rType == 2); // l2geth can pass 0 here to indicate an error | ||
require (_slot.length > 0); | ||
|
||
if (rType != 2) { | ||
// The if() avoids calling genRequestRLP unnecessarily | ||
require (rType == 2, string(genRequestRLP(methods[method_idx], _slot))); | ||
} | ||
return _slot; | ||
} | ||
|
||
/* This is called from the external contract. It takes a method | ||
selector and an abi-encoded request payload. The URL and the | ||
list of allowed methods are supplied when the contract is | ||
created. In the future some of this registration might be moved | ||
into l2geth, allowing for security measures such as TLS client | ||
certificates. A configurable timeout could also be added. | ||
*/ | ||
function TuringCall(uint32 method_idx, bytes memory _payload) | ||
public view returns (bytes memory) { | ||
require (method_idx < methods.length, "Method not registered"); | ||
require (_payload.length > 0, "Payload length was 0"); | ||
|
||
/* Initiate the request. This can't be a local function call | ||
because that would stay inside the EVM and not give l2geth | ||
a place to intercept and re-write the call. | ||
*/ | ||
bytes memory response = Self.GetResponse(method_idx, 1, _payload); | ||
return response; | ||
} | ||
} | ||
|
Oops, something went wrong.