From 2abf4be9794af52933c9538e4501b98af0ff1cf8 Mon Sep 17 00:00:00 2001 From: bitbeckers Date: Tue, 13 Oct 2020 16:01:44 +0200 Subject: [PATCH 1/4] chore(refactor): removing measure and ranges to scope down contract complexity --- contracts/SinglePlayerCommit.sol | 183 +++++++++--------------------- test/SinglePlayerCommit.deploy.ts | 54 ++++----- test/SinglePlayerCommit.ts | 12 +- 3 files changed, 84 insertions(+), 165 deletions(-) diff --git a/contracts/SinglePlayerCommit.sol b/contracts/SinglePlayerCommit.sol index f6e2d9b..f55dc62 100644 --- a/contracts/SinglePlayerCommit.sol +++ b/contracts/SinglePlayerCommit.sol @@ -7,8 +7,6 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -//TODO Do we want console.log logging, start with Activity constructor?.. - contract SinglePlayerCommit is Ownable { using SafeMath for uint256; @@ -21,26 +19,18 @@ contract SinglePlayerCommit is Ownable { /*************** DATA TYPES ***************/ - struct Measure { - string name; - bool allowed; - } - struct Activity { - string name; // e.g. "cycling" - bytes32[] measures; // keys from allowedMeasures - uint256[2][] ranges; // array of [min,max] goal values + string name; // e.g. "cycling" with list scoped to activities supported by Strava address oracle; bool allowed; } struct Commitment { address committer; // user - bytes32 activity; // key from allowedActivities - bytes32 measure; // key from allowedMeasures - uint256 goalValue; // must be within range of Activity.measures[measureIndex] - uint256 start; - uint256 end; + bytes32 activityKey; + uint256 goal; + uint256 startTime; + uint256 endTime; uint256 stake; // amount of token staked, scaled by token decimals bool exists; // flag to help check if commitment exists uint256 reportedValue; // as reported by oracle @@ -52,8 +42,8 @@ contract SinglePlayerCommit is Ownable { ***************/ event NewCommitment( address committer, - string activity, - string measure, + string activityName, + uint256 goal, uint256 startTime, uint256 endTime, uint256 stake @@ -68,11 +58,8 @@ contract SinglePlayerCommit is Ownable { mapping(bytes32 => Activity) public allowedActivities; bytes32[] public activityList; - mapping(bytes32 => Measure) public allowedMeasures; - bytes32[] public measureList; - mapping(address => Commitment) public commitments; // active commitments - // address[] public committers; // addresses with active commitments + address[] public userCommitments; // addresses with active commitments mapping(address => uint256) public balances; // current token balances uint256 public committerBalance; // sum of current token balances @@ -82,71 +69,35 @@ contract SinglePlayerCommit is Ownable { ********/ // constructor constructor( - string memory _activity, - string[] memory _measures, - uint256[2][] memory _ranges, - address _oracle, + string[] memory _activityList, + address _oracleAddress, address _token ) public { console.log("Constructor called for SinglePlayerCommit contract"); // set up token interface token = IERC20(_token); + require(_activityList.length >= 1, "SPC::constructor - activityList empty"); - // need to create fixed length bytes32 array to pass to _addActivity - uint256 len = _measures.length; - bytes32[] memory measureKeys = new bytes32[](len); - - // register measures - for (uint256 i = 0; i < len; i++) { - // register the measure - bytes32 measureKey = _addMeasure(_measures[i]); - // add its key to the array to be passed to _addActivity - measureKeys[i] = measureKey; - } - - // register activity - _addActivity(_activity, measureKeys, _ranges, _oracle); + // register allowed activities with corresponding oracle + _addActivities(_activityList, _oracleAddress); } - // fallback function (if exists) - // TODO - // view functions function getActivityName(bytes32 _activityKey) public view returns (string memory) { return allowedActivities[_activityKey].name; } - function getActivityMeasures(bytes32 _activityKey) public view returns (string[] memory measureNames) { - bytes32[] memory measures = allowedActivities[_activityKey].measures; - uint256 len = measures.length; - measureNames = new string[](len); - for (uint256 i = 0; i < len; i++) { - measureNames[i] = getMeasureName(measures[i]); - } - - return measureNames; - } - - function getMeasureName(bytes32 _measureKey) public view returns (string memory) { - return allowedMeasures[_measureKey].name; - } - // other public functions function depositAndCommit( - bytes32 _activity, - uint256 _measureIndex, + bytes32 _activityKey, uint256 _goal, uint256 _startTime, uint256 _stake, uint256 _depositAmount ) public returns (bool) { require(deposit(_depositAmount), "SPC::depositAndCommit - deposit failed"); - - require( - makeCommitment(_activity, _measureIndex, _goal, _startTime, _stake), - "SPC::depositAndCommit - commitment failed" - ); + require(makeCommitment(_activityKey, _goal, _startTime, _stake), "SPC::depositAndCommit - commitment failed"); return true; } @@ -165,8 +116,8 @@ contract SinglePlayerCommit is Ownable { } function makeCommitment( - bytes32 _activity, - uint256 _measureIndex, // index of the Activity.measures array + bytes32 _activityKey, + // uint256 _measureIndex, // index of the Activity.measures array uint256 _goal, uint256 _startTime, uint256 _stake @@ -174,18 +125,12 @@ contract SinglePlayerCommit is Ownable { console.log("makeCommitment called by %s", msg.sender); require(!commitments[msg.sender].exists, "SPC::makeCommitment - msg.sender already has a commitment"); - require(allowedActivities[_activity].allowed, "SPC::makeCommitment - activity doesn't exist or isn't allowed"); - require(allowedActivities[_activity].measures.length >= _measureIndex+1, "SPC::makeCommitment - measure index out of bounds"); - - bytes32 measure = allowedActivities[_activity].measures[_measureIndex]; - - require(allowedMeasures[measure].allowed, "SPC::makeCommitment - measure doesn't exist or isn't allowed"); + require( + allowedActivities[_activityKey].allowed, + "SPC::makeCommitment - activity doesn't exist or isn't allowed" + ); require(_startTime > block.timestamp, "SPC::makeCommitment - commitment cannot start in the past"); - - uint256[2] storage range = allowedActivities[_activity].ranges[_measureIndex]; - require(_goal >= range[0], "SPC::makeCommitment - goal is too low"); - require(_goal <= range[1], "SPC::makeCommitment - goal is too high"); - + require(_goal >= 1, "SPC::makeCommitment - goal is too low"); require(balances[msg.sender] >= _stake, "SPC::makeCommitment - insufficient token balance"); uint256 endTime = _startTime.add(7 days); @@ -193,11 +138,10 @@ contract SinglePlayerCommit is Ownable { // create commitment... Commitment memory commitment = Commitment({ committer: msg.sender, - activity: _activity, - measure: measure, - goalValue: _goal, - start: _startTime, - end: endTime, + activityKey: _activityKey, + goal: _goal, + startTime: _startTime, + endTime: endTime, stake: _stake, exists: true, reportedValue: 0, @@ -206,16 +150,8 @@ contract SinglePlayerCommit is Ownable { // ...and add it to storage commitments[msg.sender] = commitment; - // committers.push(msg.sender); - - emit NewCommitment( - msg.sender, - allowedActivities[_activity].name, - allowedMeasures[measure].name, - _startTime, - endTime, - _stake - ); + + emit NewCommitment(msg.sender, allowedActivities[_activityKey].name, _goal, _startTime, endTime, _stake); return true; } @@ -247,16 +183,13 @@ contract SinglePlayerCommit is Ownable { Commitment memory commitment = commitments[committer]; // check if commitment has ended - require(commitment.end < block.timestamp, "SPC::processCommitment - commitment is still active"); + require(commitment.endTime < block.timestamp, "SPC::processCommitment - commitment is still active"); bool met = commitment.met; uint256 stake = commitment.stake; // "delete" the expired commitment commitments[committer].exists = false; - // remove the committer from the list of committers - // committers[committer] = committers[committers.length.sub(1)]; - // committers.pop(); uint256 penalty; @@ -271,58 +204,46 @@ contract SinglePlayerCommit is Ownable { emit CommitmentEnded(committer, met, penalty); } - // function processCommitments() public returns (bool) { - // for (uint256 i = 0; i < committers.length; i.add(1)) { - // processCommitment(committers[i]); - // } - - // return true; - // } - function ownerWithdraw(uint256 amount) public onlyOwner returns (bool) { uint256 available = token.balanceOf(address(this)).sub(committerBalance); require(amount <= available, "SPC::ownerWithdraw - not enough available balance"); - require(token.transfer(msg.sender, amount), "SPC::ownerWithdraw - token transfer failed"); return true; } // internal functions + function _addActivities(string[] memory _activityList, address oracleAddress) internal { + uint256 arrayLength = _activityList.length; - function _addMeasure(string memory _name) internal returns (bytes32 measureKey) { - Measure memory measure = Measure({ name: _name, allowed: true }); - - measureKey = keccak256(abi.encode(_name)); - allowedMeasures[measureKey] = measure; - measureList.push(measureKey); + for (uint256 i = 0; i < arrayLength; i++) { + _addActivity(_activityList[i], oracleAddress); + } - return measureKey; + console.log("All provided activities added"); } - function _addActivity( - string memory _name, - bytes32[] memory _measures, - uint256[2][] memory _ranges, - address _oracle - ) internal returns (bytes32 activityKey) { - uint256 measuresLength = _measures.length; - require(measuresLength == _ranges.length, "SPC::_addActivity - measures and ranges must have same length"); - - Activity memory activity; - - activity.name = _name; - activity.oracle = _oracle; - activity.measures = _measures; - activity.ranges = _ranges; + function _addActivity(string memory _activityName, address _oracleAddress) internal returns (bytes32 activityKey) { + bytes memory activityNameBytes = bytes(_activityName); + require(activityNameBytes.length > 0, "SPC::_addActivity - _activityName empty"); + + bytes32 _activityKey = keccak256(abi.encode(_activityName)); + + Activity storage activity = allowedActivities[_activityKey]; + activity.name = _activityName; + activity.oracle = _oracleAddress; activity.allowed = true; - activityKey = keccak256(abi.encode(_name)); - allowedActivities[activityKey] = activity; - activityList.push(activityKey); + console.log( + "Registered activity %s, oracle %s, allowed %s", + allowedActivities[_activityKey].name, + allowedActivities[_activityKey].oracle, + allowedActivities[_activityKey].allowed + ); - return activityKey; + activityList.push(_activityKey); + return _activityKey; } function _changeCommitterBalance(uint256 amount, bool add) internal returns (bool) { diff --git a/test/SinglePlayerCommit.deploy.ts b/test/SinglePlayerCommit.deploy.ts index d9def05..665c789 100644 --- a/test/SinglePlayerCommit.deploy.ts +++ b/test/SinglePlayerCommit.deploy.ts @@ -1,44 +1,46 @@ import { expect } from "chai"; -import { BytesLike } from "ethers/lib/utils"; +import { BytesLike, solidityKeccak256 } from "ethers/lib/utils"; export function shouldDeployWithInitialParameters(): void { - it("has the 'biking' activity and it is allowed", async function () { - const activityKey: BytesLike = await this.singlePlayerCommit.activityList(0); - const _activityName: string = await this.singlePlayerCommit.getActivityName(activityKey); - + it("has the 'biking' and 'cycling' activity and it is allowed", async function () { + //Check biking + const _activityName: string = "biking"; + const _firstKey: BytesLike = await this.singlePlayerCommit.activityList(0); - const _activity = await this.singlePlayerCommit.allowedActivities(activityKey); + //TODO Find the way to get the expected Keccak256 output matching the first key in the list + // const _activityKey: BytesLike = solidityKeccak256(["string"], [_activityName]); + // console.log("Activitykey: ", _activityKey ) - expect(_activityName).to.equal('biking'); + const _activity = await this.singlePlayerCommit.allowedActivities(_firstKey); + console.log("Activity returned: ", _activity) + + //Check running + const _activityName2: string = "running"; + const _secondKey: BytesLike = await this.singlePlayerCommit.activityList(1); + + const _activityKey2: BytesLike = solidityKeccak256(["string"], [_activityName2]); + console.log("Activitykey: ", _activityKey2 ) + + const _activity2 = await this.singlePlayerCommit.allowedActivities(_secondKey); + console.log("Activity returned: ", _activity2) + + //Validate expect(_activity['name']).to.equal(_activityName); - // expect(_activity['measures'][0]).to.equal('km'); - // expect(_activity['ranges']).to.equal([2,1024]); expect(_activity['oracle']).to.be.properAddress; expect(_activity['allowed']).to.be.true; - // expect('getActivityName').to.be.calledOnContract(this.singlePlayerCommit); - }); - - it("has no other activities", async function () { - await expect( - this.singlePlayerCommit.activityList(1), - ).to.be.revertedWith("Transaction reverted without a reason") - - }); - it("has the 'km' measure and it is allowed", async function () { - const measureKey: BytesLike = await this.singlePlayerCommit.measureList(0); - const activityMeasure: string[] = await this.singlePlayerCommit.allowedMeasures(measureKey); - - expect(activityMeasure[0]).to.equal('km'); - expect(activityMeasure[1]).to.be.true; + expect(_activity2['name']).to.equal(_activityName2); + expect(_activity2['oracle']).to.be.properAddress; + expect(_activity2['allowed']).to.be.true; }); - it("has no other measures", async function () { + it("has no other activities", async function () { await expect( - this.singlePlayerCommit.activityList(1), + this.singlePlayerCommit.activityList(2), ).to.be.revertedWith("Transaction reverted without a reason") + }); } \ No newline at end of file diff --git a/test/SinglePlayerCommit.ts b/test/SinglePlayerCommit.ts index 581f07d..83081ca 100644 --- a/test/SinglePlayerCommit.ts +++ b/test/SinglePlayerCommit.ts @@ -20,25 +20,21 @@ setTimeout(async function () { let accounts: Signer[]; let owner: Signer; - const activity: string = "biking"; - const measures: string[] = ["km"]; - const ranges: BigNumberish[][] = [[2, 1024]]; + const supportedActivities: string[] = ["biking", "running"]; + before(async function () { console.log("Setting up environment [provider, signers, mock contracts]") - // ethers.provider = new MockProvider(); accounts = await ethers.getSigners(); owner = accounts[0]; this.oracle = await waffle.deployMockContract(owner, chainLinkArtifact); this.token = await waffle.deployMockContract(owner, daiArtifact); - console.log("Deploying SinglePlayerCommit with %s, %s, and %s", activity, measures, ranges[0]); + console.log("Deploying SinglePlayerCommit with %s", supportedActivities); const SinglePlayerCommit: ContractFactory = await ethers.getContractFactory("SinglePlayerCommit"); this.singlePlayerCommit = (await SinglePlayerCommit.deploy( - activity, - measures, - ranges, + supportedActivities, this.oracle.address, this.token.address, )) as SinglePlayerCommit; From 99f6c11a872d83c7efc396318f4cd294926130bf Mon Sep 17 00:00:00 2001 From: bitbeckers Date: Tue, 13 Oct 2020 16:08:20 +0200 Subject: [PATCH 2/4] feat(timed): added option for timed measure of activity --- contracts/SinglePlayerCommit.sol | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contracts/SinglePlayerCommit.sol b/contracts/SinglePlayerCommit.sol index f55dc62..7bb66f2 100644 --- a/contracts/SinglePlayerCommit.sol +++ b/contracts/SinglePlayerCommit.sol @@ -34,6 +34,7 @@ contract SinglePlayerCommit is Ownable { uint256 stake; // amount of token staked, scaled by token decimals bool exists; // flag to help check if commitment exists uint256 reportedValue; // as reported by oracle + bool timed; //if true, take time from API. if false, use default (distance) bool met; // whether the commitment has been met } @@ -44,6 +45,7 @@ contract SinglePlayerCommit is Ownable { address committer, string activityName, uint256 goal, + bool timed, uint256 startTime, uint256 endTime, uint256 stake @@ -92,12 +94,13 @@ contract SinglePlayerCommit is Ownable { function depositAndCommit( bytes32 _activityKey, uint256 _goal, + bool _timed, uint256 _startTime, uint256 _stake, uint256 _depositAmount ) public returns (bool) { require(deposit(_depositAmount), "SPC::depositAndCommit - deposit failed"); - require(makeCommitment(_activityKey, _goal, _startTime, _stake), "SPC::depositAndCommit - commitment failed"); + require(makeCommitment(_activityKey, _goal, _timed, _startTime, _stake), "SPC::depositAndCommit - commitment failed"); return true; } @@ -119,6 +122,7 @@ contract SinglePlayerCommit is Ownable { bytes32 _activityKey, // uint256 _measureIndex, // index of the Activity.measures array uint256 _goal, + bool _timed, uint256 _startTime, uint256 _stake ) public returns (bool) { @@ -140,6 +144,7 @@ contract SinglePlayerCommit is Ownable { committer: msg.sender, activityKey: _activityKey, goal: _goal, + timed: _timed, startTime: _startTime, endTime: endTime, stake: _stake, @@ -151,7 +156,7 @@ contract SinglePlayerCommit is Ownable { // ...and add it to storage commitments[msg.sender] = commitment; - emit NewCommitment(msg.sender, allowedActivities[_activityKey].name, _goal, _startTime, endTime, _stake); + emit NewCommitment(msg.sender, allowedActivities[_activityKey].name, _goal, _timed, _startTime, endTime, _stake); return true; } @@ -261,4 +266,4 @@ contract SinglePlayerCommit is Ownable { return true; } -} +} \ No newline at end of file From 518a2ecd6438ca078325b67822a14deb3e8614c6 Mon Sep 17 00:00:00 2001 From: bitbeckers Date: Fri, 23 Oct 2020 23:19:25 +0200 Subject: [PATCH 3/4] chore(contract): refactor to remove measures and ranges --- README.md | 19 +- contracts/SinglePlayerCommit.sol | 22 +- out/SinglePlayerCommit_flat.sol | 2210 +++++++++++++++++++++++++++++ test/SinglePlayerCommit.deploy.ts | 36 +- test/SinglePlayerCommit.user.ts | 65 +- 5 files changed, 2261 insertions(+), 91 deletions(-) create mode 100644 out/SinglePlayerCommit_flat.sol diff --git a/README.md b/README.md index 791a371..bf9c470 100644 --- a/README.md +++ b/README.md @@ -16,28 +16,13 @@ Currently Ganache and Node 14 are not playing well together. To get started: ## Features -Single Player mode features: - -- [x] Creation of Commitment -- [ ] Management of Activities -- [ ] Management of Measures -- [x] Execution of commitment settlement - #### Creation of Commitment -A commitment consists of an ```activity```, a ```measure``` for given activity, a ```start time```, and ```stake```. We will set the ```end date``` 7 days after the startdate. +A commitment consists of an ```activity```, a ```goalValue``` for given activity, a ```startTime```, and ```stake```. We will automagically set the ```endTime``` 7 days after the startdate. #### Management of Activities -An activity consists of a ```name```, a ```measure``` to express activity metrics, an array of accepted ```ranges```, and the ```oracle``` address. Activities can be enabled by setting it to ```allowed```. - -For the Single Player mode ```biking``` is the only available activity, as declared in ```scripts/deploy.ts``` - -#### Management of Measures - -A measure has a ```name``` and can be enabled by setting it to ```allowed```. - -For the Single Player mode ```km``` is the only available measure, as declared in ```scripts/deploy.ts``` +An activity consists of a ```name``` and the ```oracle``` address. Activities can be enabled by setting it to ```allowed```. #### Execution of commitment settlement diff --git a/contracts/SinglePlayerCommit.sol b/contracts/SinglePlayerCommit.sol index 7bb66f2..5590976 100644 --- a/contracts/SinglePlayerCommit.sol +++ b/contracts/SinglePlayerCommit.sol @@ -28,13 +28,12 @@ contract SinglePlayerCommit is Ownable { struct Commitment { address committer; // user bytes32 activityKey; - uint256 goal; + uint256 goalValue; uint256 startTime; uint256 endTime; uint256 stake; // amount of token staked, scaled by token decimals bool exists; // flag to help check if commitment exists uint256 reportedValue; // as reported by oracle - bool timed; //if true, take time from API. if false, use default (distance) bool met; // whether the commitment has been met } @@ -44,8 +43,7 @@ contract SinglePlayerCommit is Ownable { event NewCommitment( address committer, string activityName, - uint256 goal, - bool timed, + uint256 goalValue, uint256 startTime, uint256 endTime, uint256 stake @@ -93,14 +91,13 @@ contract SinglePlayerCommit is Ownable { // other public functions function depositAndCommit( bytes32 _activityKey, - uint256 _goal, - bool _timed, + uint256 _goalValue, uint256 _startTime, uint256 _stake, uint256 _depositAmount ) public returns (bool) { require(deposit(_depositAmount), "SPC::depositAndCommit - deposit failed"); - require(makeCommitment(_activityKey, _goal, _timed, _startTime, _stake), "SPC::depositAndCommit - commitment failed"); + require(makeCommitment(_activityKey, _goalValue, _startTime, _stake), "SPC::depositAndCommit - commitment failed"); return true; } @@ -120,9 +117,7 @@ contract SinglePlayerCommit is Ownable { function makeCommitment( bytes32 _activityKey, - // uint256 _measureIndex, // index of the Activity.measures array - uint256 _goal, - bool _timed, + uint256 _goalValue, uint256 _startTime, uint256 _stake ) public returns (bool) { @@ -134,7 +129,7 @@ contract SinglePlayerCommit is Ownable { "SPC::makeCommitment - activity doesn't exist or isn't allowed" ); require(_startTime > block.timestamp, "SPC::makeCommitment - commitment cannot start in the past"); - require(_goal >= 1, "SPC::makeCommitment - goal is too low"); + require(_goalValue > 1, "SPC::makeCommitment - goal is too low"); require(balances[msg.sender] >= _stake, "SPC::makeCommitment - insufficient token balance"); uint256 endTime = _startTime.add(7 days); @@ -143,8 +138,7 @@ contract SinglePlayerCommit is Ownable { Commitment memory commitment = Commitment({ committer: msg.sender, activityKey: _activityKey, - goal: _goal, - timed: _timed, + goalValue: _goalValue, startTime: _startTime, endTime: endTime, stake: _stake, @@ -156,7 +150,7 @@ contract SinglePlayerCommit is Ownable { // ...and add it to storage commitments[msg.sender] = commitment; - emit NewCommitment(msg.sender, allowedActivities[_activityKey].name, _goal, _timed, _startTime, endTime, _stake); + emit NewCommitment(msg.sender, allowedActivities[_activityKey].name, _goalValue, _startTime, endTime, _stake); return true; } diff --git a/out/SinglePlayerCommit_flat.sol b/out/SinglePlayerCommit_flat.sol new file mode 100644 index 0000000..1075a3f --- /dev/null +++ b/out/SinglePlayerCommit_flat.sol @@ -0,0 +1,2210 @@ +// SPDX-License-Identifier: MIT +pragma solidity >= 0.4.22 <0.7.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logByte(byte p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(byte)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} +/* SPDX-License-Identifier: MIT */ + +pragma experimental ABIEncoderV2; + + + + + + + + + + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () internal { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(_owner == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + + + + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} + + + + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + + +//TODO Do we want console.log logging, start with Activity constructor?.. + +contract SinglePlayerCommit is Ownable { + using SafeMath for uint256; + + /****************** + GLOBAL CONSTANTS + ******************/ + IERC20 public token; + uint256 BIGGEST_NUMBER = uint256(-1); + + /*************** + DATA TYPES + ***************/ + struct Measure { + string name; + bool allowed; + } + + struct Activity { + string name; // e.g. "cycling" + bytes32[] measures; // keys from allowedMeasures + uint256[2][] ranges; // array of [min,max] goal values + address oracle; + bool allowed; + } + + struct Commitment { + address committer; // user + bytes32 activity; // key from allowedActivities + bytes32 measure; // key from allowedMeasures + uint256 goalValue; // must be within range of Activity.measures[measureIndex] + uint256 start; + uint256 end; + uint256 stake; // amount of token staked, scaled by token decimals + bool exists; // flag to help check if commitment exists + uint256 reportedValue; // as reported by oracle + bool met; // whether the commitment has been met + } + + /*************** + EVENTS + ***************/ + event NewCommitment( + address committer, + string activity, + string measure, + uint256 startTime, + uint256 endTime, + uint256 stake + ); + event CommitmentEnded(address committer, bool met, uint256 amountPenalized); + event Deposit(address committer, uint256 amount); + event Withdrawal(address committer, uint256 amount); + + /****************** + INTERNAL ACCOUNTING + ******************/ + mapping(bytes32 => Activity) public allowedActivities; + bytes32[] public activityList; + + mapping(bytes32 => Measure) public allowedMeasures; + bytes32[] public measureList; + + mapping(address => Commitment) public commitments; // active commitments + // address[] public committers; // addresses with active commitments + + mapping(address => uint256) public balances; // current token balances + uint256 public committerBalance; // sum of current token balances + + /******** + FUNCTIONS + ********/ + // constructor + constructor( + string memory _activity, + string[] memory _measures, + uint256[2][] memory _ranges, + address _oracle, + address _token + ) public { + console.log("Constructor called for SinglePlayerCommit contract"); + // set up token interface + token = IERC20(_token); + + // need to create fixed length bytes32 array to pass to _addActivity + uint256 len = _measures.length; + bytes32[] memory measureKeys = new bytes32[](len); + + // register measures + for (uint256 i = 0; i < len; i++) { + // register the measure + bytes32 measureKey = _addMeasure(_measures[i]); + // add its key to the array to be passed to _addActivity + measureKeys[i] = measureKey; + } + + // register activity + _addActivity(_activity, measureKeys, _ranges, _oracle); + } + + // fallback function (if exists) + // TODO + + // view functions + + function getActivityName(bytes32 _activityKey) public view returns (string memory) { + return allowedActivities[_activityKey].name; + } + + function getActivityMeasures(bytes32 _activityKey) public view returns (string[] memory measureNames) { + bytes32[] memory measures = allowedActivities[_activityKey].measures; + uint256 len = measures.length; + measureNames = new string[](len); + for (uint256 i = 0; i < len; i++) { + measureNames[i] = getMeasureName(measures[i]); + } + + return measureNames; + } + + function getMeasureName(bytes32 _measureKey) public view returns (string memory) { + return allowedMeasures[_measureKey].name; + } + + // other public functions + function depositAndCommit( + bytes32 _activity, + uint256 _measureIndex, + uint256 _goal, + uint256 _startTime, + uint256 _stake, + uint256 _depositAmount + ) public returns (bool) { + require(deposit(_depositAmount), "SPC::depositAndCommit - deposit failed"); + + require( + makeCommitment(_activity, _measureIndex, _goal, _startTime, _stake), + "SPC::depositAndCommit - commitment failed" + ); + + return true; + } + + function deposit(uint256 amount) public returns (bool) { + console.log("Received call for depositing amount %s from sender %s", amount, msg.sender); + // make deposit + require(token.transferFrom(msg.sender, address(this), amount), "SPC::deposit - token transfer failed"); + + // update committer's balance + _changeCommitterBalance(amount, true); + + emit Deposit(msg.sender, amount); + + return true; + } + + function makeCommitment( + bytes32 _activity, + uint256 _measureIndex, // index of the Activity.measures array + uint256 _goal, + uint256 _startTime, + uint256 _stake + ) public returns (bool) { + console.log("makeCommitment called by %s", msg.sender); + + require(!commitments[msg.sender].exists, "SPC::makeCommitment - msg.sender already has a commitment"); + require(allowedActivities[_activity].allowed, "SPC::makeCommitment - activity doesn't exist or isn't allowed"); + require(allowedActivities[_activity].measures.length >= _measureIndex+1, "SPC::makeCommitment - measure index out of bounds"); + + bytes32 measure = allowedActivities[_activity].measures[_measureIndex]; + + require(allowedMeasures[measure].allowed, "SPC::makeCommitment - measure doesn't exist or isn't allowed"); + require(_startTime > block.timestamp, "SPC::makeCommitment - commitment cannot start in the past"); + + uint256[2] storage range = allowedActivities[_activity].ranges[_measureIndex]; + require(_goal >= range[0], "SPC::makeCommitment - goal is too low"); + require(_goal <= range[1], "SPC::makeCommitment - goal is too high"); + + require(balances[msg.sender] >= _stake, "SPC::makeCommitment - insufficient token balance"); + + uint256 endTime = _startTime.add(7 days); + + // create commitment... + Commitment memory commitment = Commitment({ + committer: msg.sender, + activity: _activity, + measure: measure, + goalValue: _goal, + start: _startTime, + end: endTime, + stake: _stake, + exists: true, + reportedValue: 0, + met: false + }); + + // ...and add it to storage + commitments[msg.sender] = commitment; + // committers.push(msg.sender); + + emit NewCommitment( + msg.sender, + allowedActivities[_activity].name, + allowedMeasures[measure].name, + _startTime, + endTime, + _stake + ); + + return true; + } + + function withdraw(uint256 amount) public returns (bool) { + console.log("Received call for withdrawing amount %s from sender %s", amount, msg.sender); + uint256 available = balances[msg.sender].sub(commitments[msg.sender].stake); + require(amount >= available, "SPC::withdraw - not enough balance available"); + + // remove from committer's balance + _changeCommitterBalance(amount, false); + + require(token.transfer(msg.sender, amount), "SPC::withdraw - token transfer failed"); + + emit Withdrawal(msg.sender, amount); + + return true; + } + + // TODO + function report() public returns (bool) { + // get activity data from oracle + // record activity data in commitments + return true; + } + + function processCommitment(address committer) public { + console.log("Processing commitment"); + Commitment memory commitment = commitments[committer]; + + // check if commitment has ended + require(commitment.end < block.timestamp, "SPC::processCommitment - commitment is still active"); + + bool met = commitment.met; + uint256 stake = commitment.stake; + + // "delete" the expired commitment + commitments[committer].exists = false; + // remove the committer from the list of committers + // committers[committer] = committers[committers.length.sub(1)]; + // committers.pop(); + + uint256 penalty; + + if (met) { + penalty = 0; + } else { + penalty = stake; + // remove from committer's balance + _changeCommitterBalance(penalty, false); + } + + emit CommitmentEnded(committer, met, penalty); + } + + // function processCommitments() public returns (bool) { + // for (uint256 i = 0; i < committers.length; i.add(1)) { + // processCommitment(committers[i]); + // } + + // return true; + // } + + function ownerWithdraw(uint256 amount) public onlyOwner returns (bool) { + uint256 available = token.balanceOf(address(this)).sub(committerBalance); + + require(amount <= available, "SPC::ownerWithdraw - not enough available balance"); + + require(token.transfer(msg.sender, amount), "SPC::ownerWithdraw - token transfer failed"); + + return true; + } + + // internal functions + + function _addMeasure(string memory _name) internal returns (bytes32 measureKey) { + Measure memory measure = Measure({ name: _name, allowed: true }); + + measureKey = keccak256(abi.encode(_name)); + allowedMeasures[measureKey] = measure; + measureList.push(measureKey); + + return measureKey; + } + + function _addActivity( + string memory _name, + bytes32[] memory _measures, + uint256[2][] memory _ranges, + address _oracle + ) internal returns (bytes32 activityKey) { + uint256 measuresLength = _measures.length; + require(measuresLength == _ranges.length, "SPC::_addActivity - measures and ranges must have same length"); + + Activity memory activity; + + activity.name = _name; + activity.oracle = _oracle; + activity.measures = _measures; + activity.ranges = _ranges; + activity.allowed = true; + + activityKey = keccak256(abi.encode(_name)); + allowedActivities[activityKey] = activity; + activityList.push(activityKey); + + return activityKey; + } + + function _changeCommitterBalance(uint256 amount, bool add) internal returns (bool) { + if (add) { + // increase committer's token balance + balances[msg.sender] = balances[msg.sender].add(amount); + // add to total committer balance sum + committerBalance = committerBalance.add(amount); + } else { + // decrease committer's token balance + balances[msg.sender] = balances[msg.sender].sub(amount); + // decrease total committer balance sum + committerBalance = committerBalance.sub(amount); + } + + return true; + } +} + + + diff --git a/test/SinglePlayerCommit.deploy.ts b/test/SinglePlayerCommit.deploy.ts index 665c789..18ba25c 100644 --- a/test/SinglePlayerCommit.deploy.ts +++ b/test/SinglePlayerCommit.deploy.ts @@ -4,42 +4,44 @@ import { BytesLike, solidityKeccak256 } from "ethers/lib/utils"; export function shouldDeployWithInitialParameters(): void { it("has the 'biking' and 'cycling' activity and it is allowed", async function () { + const _activityNames: string[] = ["biking", "running"]; + const _activityKeys: BytesLike[] = []; + const _activities = []; + //Check biking - const _activityName: string = "biking"; - const _firstKey: BytesLike = await this.singlePlayerCommit.activityList(0); + _activityKeys.push(await this.singlePlayerCommit.activityList(0)); //TODO Find the way to get the expected Keccak256 output matching the first key in the list // const _activityKey: BytesLike = solidityKeccak256(["string"], [_activityName]); // console.log("Activitykey: ", _activityKey ) - const _activity = await this.singlePlayerCommit.allowedActivities(_firstKey); - console.log("Activity returned: ", _activity) + _activities.push(await this.singlePlayerCommit.allowedActivities(_activityKeys[0])); + console.log("Activity returned: ", _activities[0]) //Check running - const _activityName2: string = "running"; - const _secondKey: BytesLike = await this.singlePlayerCommit.activityList(1); + _activityKeys.push(await this.singlePlayerCommit.activityList(1)); - const _activityKey2: BytesLike = solidityKeccak256(["string"], [_activityName2]); - console.log("Activitykey: ", _activityKey2 ) + // const _activityKey2: BytesLike = solidityKeccak256(["string"], [_activities[1]]); + // console.log("Activitykey: ", _activityKey2 ) - const _activity2 = await this.singlePlayerCommit.allowedActivities(_secondKey); - console.log("Activity returned: ", _activity2) + _activities.push(await this.singlePlayerCommit.allowedActivities(_activityKeys[1])); + console.log("Activity returned: ", _activities[1]) //Validate - expect(_activity['name']).to.equal(_activityName); - expect(_activity['oracle']).to.be.properAddress; - expect(_activity['allowed']).to.be.true; + expect(_activities[0]['name']).to.equal(_activityNames[0]); + expect(_activities[0]['oracle']).to.be.properAddress; + expect(_activities[0]['allowed']).to.be.true; - expect(_activity2['name']).to.equal(_activityName2); - expect(_activity2['oracle']).to.be.properAddress; - expect(_activity2['allowed']).to.be.true; + expect(_activities[1]['name']).to.equal(_activityNames[1]); + expect(_activities[1]['oracle']).to.be.properAddress; + expect(_activities[1]['allowed']).to.be.true; }); it("has no other activities", async function () { await expect( this.singlePlayerCommit.activityList(2), - ).to.be.revertedWith("Transaction reverted without a reason") + ).to.be.reverted; }); diff --git a/test/SinglePlayerCommit.user.ts b/test/SinglePlayerCommit.user.ts index 531ee9e..cb28306 100644 --- a/test/SinglePlayerCommit.user.ts +++ b/test/SinglePlayerCommit.user.ts @@ -80,13 +80,12 @@ export function userCanManageCommitments(): void { it("not make a commitment without deposited funds", async function () { //Transaction const _activity: string = await this.singlePlayerCommit.activityList(0); - const _measureIndex: number = 0; - const _goal: number = 50; + const _goalValue: number = 50; const _startTime: number = Date.now(); const _amountToStake: BigNumber = utils.parseEther("50.0"); await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), + contractWithUser.makeCommitment(_activity, _goalValue, _startTime, _amountToStake, _overrides), ).to.be.revertedWith("SPC::makeCommitment - insufficient token balance"); }); @@ -102,41 +101,26 @@ export function userCanManageCommitments(): void { //Default parameters let _activity: BytesLike = await this.singlePlayerCommit.activityList(0); - let _measureIndex: number = 0; - let _goal: number = 50; - let _startTime: number = Date.now(); + let _goalValue: number = 50; + let _startTime: number = Date.now().valueOf(); const _amountToStake: BigNumber = utils.parseEther("50.0"); //Activity _activity = '0xb16dfc4a050ca7e77c1c5f443dc473a2f03ac722e25f721ab6333875f44984f2'; await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), + contractWithUser.makeCommitment(_activity, _goalValue, _startTime, _amountToStake, _overrides), ).to.be.revertedWith("SPC::makeCommitment - activity doesn't exist or isn't allowed"); _activity = await this.singlePlayerCommit.activityList(0); - //Measure - _measureIndex = 1; - - await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), - ).to.be.revertedWith("SPC::makeCommitment - measure index out of bounds"); - _measureIndex = 0; - - //Goal - _goal = 1; + //Goal + _goalValue = 1; await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), + contractWithUser.makeCommitment(_activity, _goalValue, _startTime, _amountToStake, _overrides), ).to.be.revertedWith("SPC::makeCommitment - goal is too low"); - _goal = 9999; - - await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), - ).to.be.revertedWith("SPC::makeCommitment - goal is too high"); - - _goal = 50; + _goalValue = 50; //Start time //TODO Not reverting on time before current @@ -177,19 +161,18 @@ export function userCanManageCommitments(): void { //Transaction const _activity: string = await this.singlePlayerCommit.activityList(0); - const _measureIndex: number = 0; - const _goal: number = 50; + const _goalValue: number = 50; const _startTime: number = Date.now(); const _amountToStake: BigNumber = utils.parseEther("50.0"); - const _expectedEndTime = addDays(_startTime, 7); await this.token.mock.transfer.returns(true); await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), + contractWithUser.makeCommitment(_activity, _goalValue, _startTime, _amountToStake, _overrides), ).to.emit(this.singlePlayerCommit, "NewCommitment"); //Validate const commitment = await this.singlePlayerCommit.commitments(user.getAddress()); + const activityName = await this.singlePlayerCommit.getActivityName(commitment.activityKey); const _updatedUserBalance: BigNumber = await user.getBalance(); const _updatedUserDaiBalanceInContract: BigNumber = await this.singlePlayerCommit.balances(user.getAddress()); const _updatedCommitterBalance: BigNumber = await this.singlePlayerCommit.committerBalance.call(); @@ -199,12 +182,11 @@ export function userCanManageCommitments(): void { expect(_updatedCommitterBalance).to.equal(utils.parseEther("100.0")); expect(commitment.committer).to.be.properAddress; - expect(await this.singlePlayerCommit.getActivityName(commitment.activity)).to.equal("biking"); - expect(await this.singlePlayerCommit.getMeasureName(commitment.measure)).to.equal("km"); - expect(commitment.goalValue.toNumber()).to.equal(_goal); + expect(activityName).to.equal("biking"); + expect(commitment.goalValue.toNumber()).to.equal(_goalValue); expect(commitment.stake).to.equal(_amountToStake); - expect(commitment.start).to.equal(_startTime); - expect(commitment.end).to.not.be.undefined; //milliseconds, timing make equal difficult + expect(commitment.startTime).to.equal(_startTime); + expect(commitment.endTime).to.not.be.undefined; //milliseconds, timing make equal difficult }); it("not make more than one commitment", async function () { @@ -214,14 +196,13 @@ export function userCanManageCommitments(): void { //Transaction const _activity: BytesLike = await this.singlePlayerCommit.activityList(0); - const _measureIndex: number = 0; const _goal: number = 50; const _startTime: number = Date.now(); const _amountToStake: BigNumber = utils.parseEther("50.0"); await this.token.mock.transfer.returns(true); await expect( - contractWithUser.makeCommitment(_activity, _measureIndex, _goal, _startTime, _amountToStake, _overrides), + contractWithUser.makeCommitment(_activity, _goal, _startTime, _amountToStake, _overrides), ).to.be.revertedWith("SPC::makeCommitment - msg.sender already has a commitment"); }); @@ -249,6 +230,7 @@ export function userCanManageCommitments(): void { "CommitmentEnded", ); expect(commitment.exists).to.be.false; + console.log("LALALALALLALAL"); }); //TODO Currently failing on active commitment; need fixture or cleanup @@ -265,8 +247,7 @@ export function userCanManageCommitments(): void { //Transaction const _activity: BytesLike = await this.singlePlayerCommit.activityList(0); - const _measureIndex: number = 0; - const _goal: number = 50; + const _goalValue: number = 50; const _startTime: number = Date.now(); const _amountToStake: BigNumber = utils.parseEther("50.0"); const _amountToDeposit: BigNumber = utils.parseEther("100.0"); @@ -276,15 +257,14 @@ export function userCanManageCommitments(): void { await expect( contractWithUser.depositAndCommit( _activity, - _measureIndex, - _goal, + _goalValue, _startTime, _amountToStake, _amountToDeposit, _overrides, ), ).to.emit(this.singlePlayerCommit, "NewCommitment") - .withArgs(await user.getAddress(), _activity, _measureIndex, _startTime, _expectedEndTime,_amountToStake); + .withArgs(await user.getAddress(), _activity, _goalValue, _startTime, _expectedEndTime,_amountToStake); // expect("transferFrom").to.be.calledOnContract(this.token); // expect("deposit").to.be.calledOnContract(this.singlePlayerCommit); @@ -302,8 +282,7 @@ export function userCanManageCommitments(): void { expect(commitment.committer).to.be.properAddress; expect(await this.singlePlayerCommit.getActivityName(commitment.activity)).to.equal("biking"); - expect(await this.singlePlayerCommit.getMeasureName(commitment.measure)).to.equal("km"); - expect(commitment.goalValue.toNumber()).to.equal(_goal); + expect(commitment.goalValue.toNumber()).to.equal(_goalValue); expect(commitment.stake).to.equal(_amountToStake); expect(commitment.start).to.equal(_startTime); }); From ca3cebd111bfb5ba09f35615d05ad7670f3c14dc Mon Sep 17 00:00:00 2001 From: bitbeckers Date: Mon, 26 Oct 2020 11:40:48 +0100 Subject: [PATCH 4/4] chore(review): updated test declaration based on review comment --- test/SinglePlayerCommit.deploy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SinglePlayerCommit.deploy.ts b/test/SinglePlayerCommit.deploy.ts index 18ba25c..63b7c2a 100644 --- a/test/SinglePlayerCommit.deploy.ts +++ b/test/SinglePlayerCommit.deploy.ts @@ -3,7 +3,7 @@ import { BytesLike, solidityKeccak256 } from "ethers/lib/utils"; export function shouldDeployWithInitialParameters(): void { - it("has the 'biking' and 'cycling' activity and it is allowed", async function () { + it("has the 'biking' and 'running' activity and it is allowed", async function () { const _activityNames: string[] = ["biking", "running"]; const _activityKeys: BytesLike[] = []; const _activities = [];