Skip to content

Commit

Permalink
Add pay function
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaStebaev committed Oct 26, 2023
1 parent dadde0e commit 88c329e
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 6 deletions.
17 changes: 17 additions & 0 deletions contracts/DateTimeUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ type Year is uint256;
type Timestamp is uint256;

using DateTimeUtils for Timestamp global;
using {
monthsLess as <,
monthsEqual as ==,
monthsGreater as >
} for Months global;

function monthsLess(Months left, Months right) pure returns (bool result) {
return Months.unwrap(left) < Months.unwrap(right);
}

function monthsEqual(Months a, Months b) pure returns (bool result) {
return !(a < b) && !(b < a);
}

function monthsGreater(Months left, Months right) pure returns (bool result) {
return !(left < right) && !(left == right);
}

library DateTimeUtils {
function timestamp() internal view returns (Timestamp timestampValue) {
Expand Down
92 changes: 86 additions & 6 deletions contracts/Paymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,39 @@
along with Paymaster. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity ^0.8.18;
pragma solidity ^0.8.19;

// cspell:words structs
// cspell:words structs IERC20

import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {AccessManagedUpgradeable}
from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";

import {
SchainPriceIsNotSet,
SkaleTokenIsNotSet,
SklPriceIsNotSet
} from "./errors/Parameters.sol";
import {
ReplenishmentPeriodIsTooBig,
TooSmallAllowance,
TransferFailure
} from "./errors/Replenishment.sol";
import {SchainNotFound, SchainAddingError, SchainDeletionError} from "./errors/Schain.sol";
import {ValidatorNotFound, ValidatorAddingError, ValidatorDeletionError} from "./errors/Validator.sol";
import {IPaymaster, SchainHash, ValidatorId} from "./interfaces/IPaymaster.sol";
import {
IPaymaster,
SchainHash,
USD,
ValidatorId
} from "./interfaces/IPaymaster.sol";
import {SKL} from "./types/Skl.sol";
import {
DateTimeUtils,
Timestamp
Timestamp,
Months
} from "./DateTimeUtils.sol";


Expand All @@ -59,6 +77,11 @@ contract Paymaster is AccessManagedUpgradeable, IPaymaster {
mapping(ValidatorId => Validator) public validators;
EnumerableSet.UintSet private _validatorIds;

Months public maxReplenishmentPeriod;
USD public schainPricePerMonth;
USD public oneSklPrice;
IERC20 public skaleToken;

function addSchain(string calldata name) external override restricted {
SchainHash schainHash = SchainHash.wrap(keccak256(abi.encodePacked(name)));
Schain memory schain = Schain({
Expand Down Expand Up @@ -97,9 +120,50 @@ contract Paymaster is AccessManagedUpgradeable, IPaymaster {
validator.activeNodesAmount = Math.min(amount, validator.nodesAmount);
}

// function pay(SchainHash schainHash, Months duration) external {
function setMaxReplenishmentPeriod(Months months) external override restricted {
maxReplenishmentPeriod = months;
}

function setSchainPrice(USD price) external override restricted {
schainPricePerMonth = price;
}

function setSklPrice(USD price) external override restricted {
oneSklPrice = price;
}

function setSkaleToken(IERC20 token) external override restricted {
skaleToken = token;
}

function pay(SchainHash schainHash, Months duration) external override {
if (duration > maxReplenishmentPeriod) {
revert ReplenishmentPeriodIsTooBig();
}

Schain storage schain = _getSchain(schainHash);
SKL cost = _toSKL(_getCost(duration));

if (address(skaleToken) == address(0)) {
revert SkaleTokenIsNotSet();
}
SKL allowance = SKL.wrap(
skaleToken.allowance(_msgSender(), address(this))
);
if (allowance < cost) {
revert TooSmallAllowance({
spender: address(this),
required: SKL.unwrap(cost),
allowed: SKL.unwrap(allowance)
});
}

// }
if (!skaleToken.transferFrom(_msgSender(), address(this), SKL.unwrap(cost))) {
revert TransferFailure();
}

schain.paidUntil = schain.paidUntil.add(duration);
}

// Private

Expand Down Expand Up @@ -146,4 +210,20 @@ contract Paymaster is AccessManagedUpgradeable, IPaymaster {
revert ValidatorNotFound(id);
}
}

function _toSKL(USD amount) private view returns (SKL result) {
if (oneSklPrice == USD.wrap(0)) {
revert SklPriceIsNotSet();
}
result = SKL.wrap(
USD.unwrap(amount) * 1e18 / USD.unwrap(oneSklPrice)
);
}

function _getCost(Months period) private view returns (USD cost) {
if (schainPricePerMonth == USD.wrap(0)) {
revert SchainPriceIsNotSet();
}
cost = USD.wrap(Months.unwrap(period) * USD.unwrap(schainPricePerMonth));
}
}
27 changes: 27 additions & 0 deletions contracts/errors/Parameters.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: AGPL-3.0-only

/*
Parameters.sol - Paymaster
Copyright (C) 2023-Present SKALE Labs
@author Dmytro Stebaiev
Paymaster is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Paymaster is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Paymaster. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity ^0.8.18;


error SchainPriceIsNotSet();
error SkaleTokenIsNotSet();
error SklPriceIsNotSet();
31 changes: 31 additions & 0 deletions contracts/errors/Replenishment.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: AGPL-3.0-only

/*
Replenishment.sol - Paymaster
Copyright (C) 2023-Present SKALE Labs
@author Dmytro Stebaiev
Paymaster is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Paymaster is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Paymaster. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity ^0.8.18;


error ReplenishmentPeriodIsTooBig();
error TooSmallAllowance(
address spender,
uint256 required,
uint256 allowed
);
error TransferFailure();
12 changes: 12 additions & 0 deletions contracts/interfaces/IPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@

pragma solidity ^0.8.18;

// cspell:words IERC20

import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";

import {Months} from "../DateTimeUtils.sol";
import {USD} from "../types/Usd.sol";


type SchainHash is bytes32;
type ValidatorId is uint256;
Expand All @@ -32,4 +39,9 @@ interface IPaymaster {
function removeValidator(ValidatorId id) external;
function setNodesAmount(ValidatorId id, uint256 amount) external;
function setActiveNodes(ValidatorId id, uint256 amount) external;
function setMaxReplenishmentPeriod(Months months) external;
function setSchainPrice(USD price) external;
function setSklPrice(USD price) external;
function setSkaleToken(IERC20 token) external;
function pay(SchainHash schainHash, Months duration) external;
}
33 changes: 33 additions & 0 deletions contracts/types/Skl.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: AGPL-3.0-only

/*
Skl.sol - Paymaster
Copyright (C) 2023-Present SKALE Labs
@author Dmytro Stebaiev
Paymaster is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Paymaster is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Paymaster. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity ^0.8.18;


type SKL is uint256;

using {
sklLess as <
} for SKL global;

function sklLess(SKL left, SKL right) pure returns (bool result) {
return SKL.unwrap(left) < SKL.unwrap(right);
}
33 changes: 33 additions & 0 deletions contracts/types/Usd.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: AGPL-3.0-only

/*
Usd.sol - Paymaster
Copyright (C) 2023-Present SKALE Labs
@author Dmytro Stebaiev
Paymaster is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Paymaster is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Paymaster. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity ^0.8.18;


type USD is uint256;

function usdEquals(USD a, USD b) pure returns (bool result) {
return USD.unwrap(a) == USD.unwrap(b);
}

using {
usdEquals as ==
} for USD global;

0 comments on commit 88c329e

Please sign in to comment.