Skip to content

Commit

Permalink
Mint signature (oncyberio#22)
Browse files Browse the repository at this point in the history
* wip

* mint signature

* ordering

* signature mint and coverage check

* github actions ci root

* ci node version

* minted counter
  • Loading branch information
julesGoullee authored Nov 25, 2021
1 parent 6b8bfbe commit 574631d
Show file tree
Hide file tree
Showing 29 changed files with 3,201 additions and 1,197 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
node-version: 16.x
- uses: actions/cache@v2
with:
path: '**/node_modules'
Expand All @@ -32,7 +32,11 @@ jobs:
env:
CI: true
- name: Testing
run: npm test
run: cd packages/contracts && npm run test:coverage
env:
CI: true
- name: Testing Coverage Check
run: cd packages/contracts && npm run test:coverage:check
env:
CI: true
lint:
Expand All @@ -43,7 +47,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
node-version: 16.x
- uses: actions/cache@v2
with:
path: '**/node_modules'
Expand Down
12 changes: 12 additions & 0 deletions .run/test_coverage_check.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="test:coverage:check" type="js.build_tools.npm" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/packages/contracts/package.json" />
<command value="run" />
<scripts>
<script value="test:coverage:check" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>
131 changes: 85 additions & 46 deletions packages/contracts/contracts/CyberDropBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,45 @@ contract CyberDropBase is CyberTokenBase {

event DropCreated(address indexed account, uint256 indexed tokenId);

function getDrop(uint256 _tokenId)
function dropMintCounter(uint256 _tokenId, address _minter)
public
view
returns (LibDropStorage.Drop memory)
returns (uint256 dropMintCounter)
{
LibDropStorage.Drop memory drop = LibDropStorage.layout().drops[_tokenId];
require(drop.timeStart != 0, 'DNE');
LibDropStorage.Drop storage drop = LibDropStorage.layout().drops[_tokenId];
require(drop.priceStart != 0, 'DNE');
return drop.mintCounter[_minter].current();
}

return drop;
function getDrop(uint256 _tokenId)
public
view
returns (
uint256 timeStart,
uint256 timeEnd,
uint256 priceStart,
uint256 priceEnd,
uint256 stepDuration,
uint256 amountCap,
uint256 shareCyber,
address creator,
uint256 minted
)
{
LibDropStorage.Drop storage drop = LibDropStorage.layout().drops[_tokenId];
require(drop.priceStart != 0, 'DNE');

return (
drop.timeStart,
drop.timeEnd,
drop.priceStart,
drop.priceEnd,
drop.stepDuration,
drop.amountCap,
drop.shareCyber,
drop.creator,
drop.minted.current()
);
}

function createDrop(
Expand All @@ -36,9 +66,9 @@ contract CyberDropBase is CyberTokenBase {
uint256 _amountCap,
uint256 _shareCyber,
bytes memory _signature
) public returns (uint256 _tokenId) {
) public returns (uint256 tokenId) {
require(_timeEnd - _timeStart >= _stepDuration && _stepDuration > 0, 'IT');
require(_priceStart >= _priceEnd, 'IP');
require(_priceStart >= _priceEnd && _priceStart > 0, 'IP');
require(_shareCyber <= 100, 'ISO');

address sender = _msgSender();
Expand All @@ -59,50 +89,64 @@ contract CyberDropBase is CyberTokenBase {
.toEthSignedMessageHash()
.recover(_signature);
require(recoveredAddress == LibAppStorage.layout().manager, 'NM');
tokenId = LibAppStorage.layout().totalSupply.current();

// Effects
_tokenId = LibAppStorage.layout().totalSupply.current();
setTokenURI(_tokenId, _uri);
setTokenURI(tokenId, _uri);
LibAppStorage.layout().totalSupply.increment();
LibAppStorage.layout().minterNonce[sender].increment();
LibDropStorage.Drop memory drop = LibDropStorage.Drop({
timeStart: _timeStart,
timeEnd: _timeEnd,
priceStart: _priceStart,
priceEnd: _priceEnd,
stepDuration: _stepDuration,
amountCap: _amountCap,
shareCyber: _shareCyber,
creator: payable(sender),
minted: 0
});
LibDropStorage.layout().drops[_tokenId] = drop;

emit DropCreated(sender, _tokenId);

return _tokenId;

LibDropStorage.layout().drops[tokenId].timeStart = _timeStart;
LibDropStorage.layout().drops[tokenId].timeEnd = _timeEnd;
LibDropStorage.layout().drops[tokenId].priceStart = _priceStart;
LibDropStorage.layout().drops[tokenId].priceEnd = _priceEnd;
LibDropStorage.layout().drops[tokenId].stepDuration = _stepDuration;
LibDropStorage.layout().drops[tokenId].amountCap = _amountCap;
LibDropStorage.layout().drops[tokenId].shareCyber = _shareCyber;
LibDropStorage.layout().drops[tokenId].creator = payable(sender);

emit DropCreated(sender, tokenId);
}

function mint(uint256 _tokenId) public payable returns (bool) {
function mint(uint256 _tokenId, bytes memory _signature)
public
payable
returns (bool success)
{
address sender = _msgSender();
LibDropStorage.Drop storage drop = LibDropStorage.layout().drops[_tokenId];

if (drop.amountCap != 0) {
require(drop.minted.current() < drop.amountCap, 'CR');
}

require(
block.timestamp > drop.timeStart && block.timestamp <= drop.timeEnd,
'OOT'
);

if (drop.amountCap != 0) {
require(drop.minted < drop.amountCap, 'CR');
}

uint256 price = getMintPriceForDrop(drop);
uint256 timeSpent = block.timestamp - drop.timeStart;
uint256 duration = drop.timeEnd - drop.timeStart;
uint256 price = getPriceFor(
timeSpent,
duration,
drop.priceStart,
drop.priceEnd,
drop.stepDuration
);
require(msg.value >= price, 'IA');
uint256 amountOnCyber = (msg.value * drop.shareCyber) / 100;
uint256 amountCreator = msg.value - amountOnCyber;

uint256 senderDropNonce = drop.mintCounter[sender].current();
bytes memory _message = abi.encodePacked(_tokenId, sender, senderDropNonce);
address recoveredAddress = keccak256(_message)
.toEthSignedMessageHash()
.recover(_signature);
require(recoveredAddress == LibAppStorage.layout().manager, 'NM');

// Effects
drop.minted += 1;
drop.minted.increment();
drop.mintCounter[sender].increment();
_safeMint(sender, _tokenId, 1, '');
drop.creator.transfer(amountCreator);
payable(LibAppStorage.layout().oncyber).transfer(amountOnCyber);
Expand All @@ -115,27 +159,22 @@ contract CyberDropBase is CyberTokenBase {
function getMintPriceForToken(uint256 _tokenId)
public
view
returns (uint256)
returns (uint256 mintPrice)
{
LibDropStorage.Drop storage drop = LibDropStorage.layout().drops[_tokenId];
require(drop.priceStart != 0, 'DNE');

if (drop.amountCap != 0) {
require(drop.minted.current() < drop.amountCap, 'CR');
}

require(
block.timestamp > drop.timeStart && block.timestamp <= drop.timeEnd,
'OOT'
);
if (drop.amountCap != 0) {
require(drop.minted < drop.amountCap, 'CR');
}
return getMintPriceForDrop(drop);
}

function getMintPriceForDrop(LibDropStorage.Drop memory drop)
public
view
returns (uint256)
{
uint256 timeSpent = block.timestamp - drop.timeStart;
uint256 duration = drop.timeEnd - drop.timeStart;

return
getPriceFor(
timeSpent,
Expand All @@ -152,7 +191,7 @@ contract CyberDropBase is CyberTokenBase {
uint256 _priceStart,
uint256 _priceEnd,
uint256 _stepDuration
) public pure returns (uint256) {
) public pure returns (uint256 price) {
// https://www.desmos.com/calculator/oajpdvew5q
// f\left(x\right)=\frac{s\ \cdot d\ +\ \operatorname{mod}\left(x,\ g\right)\ \cdot\ \left(s\ -\ l\right)\ -\ x\ \cdot\ \left(s\ -\ l\right)\ \ }{d}
// (s * d + (x % g) * (s - l) - x * (s - l) / d
Expand Down
12 changes: 8 additions & 4 deletions packages/contracts/contracts/CyberTokenBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,23 @@ contract CyberTokenBase is BaseRelayRecipient, ERC1155URI {
LibAppStorage.layout().oncyber = _oncyber;
}

function totalSupply() public view returns (uint256) {
function totalSupply() public view returns (uint256 totalSupply) {
return LibAppStorage.layout().totalSupply.current();
}

function manager() public view returns (address) {
function manager() public view returns (address manager) {
return LibAppStorage.layout().manager;
}

function oncyber() public view returns (address) {
function oncyber() public view returns (address oncyber) {
return LibAppStorage.layout().oncyber;
}

function minterNonce(address _minter) public view returns (uint256) {
function minterNonce(address _minter)
public
view
returns (uint256 minterNonce)
{
return LibAppStorage.layout().minterNonce[_minter].current();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
pragma solidity 0.8.9;

//import 'hardhat/console.sol';
import '../CyberDropBase.sol';
import '../../CyberDropBase.sol';

contract CyberDestinationFactoryFacet is CyberDropBase {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
pragma solidity 0.8.9;

//import 'hardhat/console.sol';
import '../CyberDropBase.sol';
import '../../CyberDropBase.sol';

contract CyberDestinationUtilityFactoryFacet is CyberDropBase {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
pragma solidity 0.8.9;

//import 'hardhat/console.sol';
import '../CyberDropBase.sol';
import '../../CyberDropBase.sol';

contract CyberObjectFactoryFacet is CyberDropBase {}
4 changes: 3 additions & 1 deletion packages/contracts/contracts/libraries/LibDropStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity 0.8.9;

//import 'hardhat/console.sol';
import '@openzeppelin/contracts/utils/Counters.sol';

library LibDropStorage {
bytes32 public constant STORAGE_SLOT = keccak256('drop.app.storage');
Expand All @@ -15,7 +16,8 @@ library LibDropStorage {
uint256 amountCap;
uint256 shareCyber;
address payable creator;
uint256 minted;
Counters.Counter minted;
mapping(address => Counters.Counter) mintCounter;
}

struct Layout {
Expand Down
17 changes: 17 additions & 0 deletions packages/contracts/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,20 @@ export async function signCreateDropRequest(

return signer.signMessage(pHash)
}

export async function signMintRequest(
tokenId: number,
creator: string,
nonce: number,
signer: Signer
): Promise<string> {
const pTokenId = utils.hexZeroPad(BigNumber.from(tokenId).toHexString(), 32)
const pNonce = utils.hexZeroPad(BigNumber.from(nonce).toHexString(), 32)
const pCreator = utils.arrayify(creator)
const message = utils.concat([pTokenId, pCreator, pNonce])

const hash = utils.keccak256(message)
const pHash = utils.arrayify(hash)

return signer.signMessage(pHash)
}
Loading

0 comments on commit 574631d

Please sign in to comment.