Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(issuer): Enable the batchIssue() method in ERC1888 #2514

Merged
merged 11 commits into from
Jun 18, 2021
3,075 changes: 1,689 additions & 1,386 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CertificateUtils } from '@energyweb/issuer';
import { CertificateBatchOperations } from '@energyweb/issuer';
import { ISuccessResponse, ResponseFailure, ResponseSuccess } from '@energyweb/origin-backend-core';
import { BigNumber } from 'ethers';
import { HttpStatus } from '@nestjs/common';
Expand Down Expand Up @@ -38,7 +38,7 @@ export class BulkClaimCertificatesHandler implements ICommandHandler<BulkClaimCe
}

try {
const bulkClaimTx = await CertificateUtils.claimCertificates(
const bulkClaimTx = await CertificateBatchOperations.claimCertificates(
certificatesToClaim.map((cert) => cert.id),
claimData,
blockchainProperties.wrap(),
Expand Down
42 changes: 21 additions & 21 deletions packages/traceability/issuer/contracts/ERC1888/IERC1888.sol
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

interface ERC1888 is IERC1155 {
interface ERC1888 is IERC1155 {

struct Certificate {
int256 topic;
address issuer; // msg.sender
bytes validityData; // call data
uint256 topic;
address issuer;
bytes validityData;
bytes data;
}

event IssuanceSingle(address indexed _issuer, int256 indexed _topic, uint256 _id);
event IssuanceBatch(address indexed _issuer, int256[] indexed _topics, uint256[] _ids);

event ClaimSingle(address indexed _claimIssuer, address indexed _claimSubject, int256 indexed _topic, uint256 _id, uint256 _value, bytes _claimData);
event ClaimBatch(address indexed _claimIssuer, address indexed _claimSubject, int256[] indexed _topics, uint256[] _ids, uint256[] _values, bytes[] _claimData);

function issue(address _to, bytes calldata _validityData, int256 _topic, uint256 _value, bytes calldata _data) external returns (uint256);
// function batchIssue(bytes[] _data, uint256[] _topics, uint256[] _value, bytes32[] _signatures) external returns(uint256[]);

function safeTransferAndClaimFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data, bytes calldata _claimData) external;
function safeBatchTransferAndClaimFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data, bytes[] calldata _claimData) external;

function getCertificate(uint256 _id) external view returns (address issuer, int256 topic, bytes calldata validityCall, bytes calldata data);
function claimedBalanceOf(address _owner, uint256 _id) external view returns (uint256);
function claimedBalanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
event IssuanceSingle(address indexed _issuer, uint256 indexed _topic, uint256 _id, uint256 _value);
event IssuanceBatch(address indexed _issuer, uint256 indexed _topic, uint256[] _ids, uint256[] _values);
event ClaimSingle(address indexed _claimIssuer, address indexed _claimSubject, uint256 indexed _topic, uint256 _id, uint256 _value, bytes _claimData);
event ClaimBatch(address indexed _claimIssuer, address indexed _claimSubject, uint256[] indexed _topics, uint256[] _ids, uint256[] _values, bytes[] _claimData);
function issue(address _to, bytes calldata _validityData, uint256 _topic, uint256 _value, bytes calldata _issuanceData) external returns (uint256);
function batchIssue(address _to, bytes memory _issuanceData, uint256 _topic, uint256[] memory _values, bytes[] memory _validityCalls) external returns(uint256[] memory);
function safeTransferAndClaimFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data, bytes calldata _claimData) external;
function safeBatchTransferAndClaimFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data, bytes[] calldata _claimData) external;

function getCertificate(uint256 _id) external view returns (address issuer, uint256 topic, bytes memory validityCall, bytes memory data);
function claimedBalanceOf(address _owner, uint256 _id) external view returns (uint256);
function claimedBalanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
}
96 changes: 88 additions & 8 deletions packages/traceability/issuer/contracts/Issuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import "./Registry.sol";

contract Issuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
event CertificationRequested(address indexed _owner, uint256 indexed _id);
event CertificationRequestedBatch(address[] indexed _owners, uint256[] indexed _id);
event CertificationRequestApproved(address indexed _owner, uint256 indexed _id, uint256 indexed _certificateId);
event CertificationRequestBatchApproved(address[] indexed _owners, uint256[] indexed _ids, uint256[] indexed _certificateIds);
event CertificationRequestRevoked(address indexed _owner, uint256 indexed _id);

event CertificateRevoked(uint256 indexed _certificateId);

int public certificateTopic;
uint256 public certificateTopic;
Registry public registry;
address public privateIssuer;

Expand All @@ -33,7 +35,7 @@ contract Issuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
address sender;
}

function initialize(int _certificateTopic, address _registry) public initializer {
function initialize(uint256 _certificateTopic, address _registry) public initializer {
require(_registry != address(0), "Issuer::initialize: Cannot use address 0x0 as registry address.");

certificateTopic = _certificateTopic;
Expand Down Expand Up @@ -74,13 +76,37 @@ contract Issuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
return id;
}

function requestCertificationForBatch(bytes[] memory _data, address[] memory _owners) public returns (uint256[] memory) {
uint256[] memory requestIds = new uint256[](_data.length);

for (uint256 i = 0; i < _data.length; i++) {
uint256 id = i + _latestCertificationRequestId + 1;

_certificationRequests[id] = CertificationRequest({
owner: _owners[i],
data: _data[i],
approved: false,
revoked: false,
sender: _msgSender()
});

requestIds[i] = id;
}

emit CertificationRequestedBatch(_owners, requestIds);

_latestCertificationRequestId = requestIds[requestIds.length - 1];

return requestIds;
}

function requestCertification(bytes calldata _data) external returns (uint256) {
return requestCertificationFor(_data, _msgSender());
}

function isRequestValid(uint256 _requestId) external view returns (bool) {
CertificationRequest memory request = _certificationRequests[_requestId];
uint certificateId = requestToCertificate[_requestId];
uint256 certificateId = requestToCertificate[_requestId];

return _requestId <= _latestCertificationRequestId
&& request.approved
Expand Down Expand Up @@ -109,30 +135,84 @@ contract Issuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {

function approveCertificationRequest(
uint256 _requestId,
uint256 _value,
bytes memory _validityData
uint256 _value
) public returns (uint256) {
require(_msgSender() == owner() || _msgSender() == privateIssuer, "Issuer::approveCertificationRequest: caller is not the owner or private issuer contract");
require(_requestNotApprovedOrRevoked(_requestId), "Issuer::approveCertificationRequest: request already approved or revoked");

CertificationRequest storage request = _certificationRequests[_requestId];
request.approved = true;

uint256 certificateId = registry.issue(request.owner, _validityData, certificateTopic, _value, request.data);
uint256 certificateId = registry.issue(
request.owner,
abi.encodeWithSignature("isRequestValid(uint256)",_requestId),
certificateTopic,
_value,
request.data
);

requestToCertificate[_requestId] = certificateId;

emit CertificationRequestApproved(request.owner, _requestId, certificateId);

return certificateId;
}

function approveCertificationRequestBatch(
uint256[] memory _requestIds,
uint256[] memory _values
) public returns (uint256[] memory) {
require(_msgSender() == owner() || _msgSender() == privateIssuer, "Issuer::approveCertificationRequestBatch: caller is not the owner or private issuer contract");

for (uint256 i = 0; i < _requestIds.length; i++) {
require(_requestNotApprovedOrRevoked(_requestIds[i]), "Issuer::approveCertificationRequestBatch: request already approved or revoked");
}

address[] memory owners = new address[](_requestIds.length);
bytes[] memory data = new bytes[](_requestIds.length);
bytes[] memory validityData = new bytes[](_requestIds.length);

for (uint256 i = 0; i < _requestIds.length; i++) {
CertificationRequest storage request = _certificationRequests[_requestIds[i]];
request.approved = true;

owners[i] = request.owner;
data[i] = request.data;
validityData[i] = abi.encodeWithSignature("isRequestValid(uint256)",_requestIds[i]);
}

uint256[] memory certificateIds = registry.batchIssueMultiple(
owners,
data,
certificateTopic,
_values,
validityData
);

for (uint256 i = 0; i < _requestIds.length; i++) {
requestToCertificate[_requestIds[i]] = certificateIds[i];
}

emit CertificationRequestBatchApproved(owners, _requestIds, certificateIds);

return certificateIds;
}

function issue(address _to, uint256 _value, bytes memory _data) public onlyOwner returns (uint256) {
uint256 requestId = requestCertificationFor(_data, _to);

return approveCertificationRequest(
requestId,
_value,
abi.encodeWithSignature("isRequestValid(uint256)",requestId)
_value
);
}

function issueBatch(address[] memory _to, uint256[] memory _values, bytes[] memory _data) public onlyOwner returns (uint256[] memory) {
uint256[] memory requestIds = requestCertificationForBatch(_data, _to);

return approveCertificationRequestBatch(
requestIds,
_values
);
}

Expand Down
24 changes: 11 additions & 13 deletions packages/traceability/issuer/contracts/PrivateIssuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,15 @@ contract PrivateIssuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
Certification requests
*/

function getCertificateCommitment(uint certificateId) public view returns (bytes32) {
function getCertificateCommitment(uint256 certificateId) public view returns (bytes32) {
return _commitments[certificateId];
}

function approveCertificationRequestPrivate(
uint256 _requestId,
bytes32 _commitment,
bytes memory _validityData
bytes32 _commitment
) public onlyOwner returns (uint256) {
uint256 certificateId = issuer.approveCertificationRequest(_requestId, 0, _validityData);
uint256 certificateId = issuer.approveCertificationRequest(_requestId, 0);
_updateCommitment(certificateId, 0x0, _commitment);

Issuer.CertificationRequest memory request = issuer.getCertificationRequest(_requestId); // TO-DO: get storage instead of memory
Expand All @@ -83,8 +82,7 @@ contract PrivateIssuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {

return approveCertificationRequestPrivate(
requestId,
_commitment,
abi.encodeWithSignature("isRequestValid(uint256)",requestId)
_commitment
);
}

Expand Down Expand Up @@ -137,18 +135,18 @@ contract PrivateIssuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
return _requestMigrateToPublicFor(_certificateId, _ownerAddressLeafHash, _msgSender());
}

function getPrivateTransferRequest(uint _certificateId) external view onlyOwner returns (PrivateTransferRequest memory) {
function getPrivateTransferRequest(uint256 _certificateId) external view onlyOwner returns (PrivateTransferRequest memory) {
return _requestPrivateTransferStorage[_certificateId];
}

function getMigrationRequest(uint _requestId) external view onlyOwner returns (RequestStateChange memory) {
function getMigrationRequest(uint256 _requestId) external view onlyOwner returns (RequestStateChange memory) {
return _requestMigrateToPublicStorage[_requestId];
}

function getMigrationRequestId(uint _certificateId) external view onlyOwner returns (uint256 _migrationRequestId) {
function getMigrationRequestId(uint256 _certificateId) external view onlyOwner returns (uint256 _migrationRequestId) {
bool found = false;

for (uint i = 1; i <= _requestMigrateToPublicNonce; i++) {
for (uint256 i = 1; i <= _requestMigrateToPublicNonce; i++) {
if (_requestMigrateToPublicStorage[i].certificateId == _certificateId) {
found = true;
return i;
Expand Down Expand Up @@ -187,7 +185,7 @@ contract PrivateIssuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {

function validateOwnershipProof(
address _ownerAddress,
uint _volume,
uint256 _volume,
string memory _salt,
bytes32 _rootHash,
Proof[] memory _proof
Expand Down Expand Up @@ -224,10 +222,10 @@ contract PrivateIssuer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
emit CommitmentUpdated(_msgSender(), _id, _commitment);
}

function _migrationRequestExists(uint _certificateId) private view returns (bool) {
function _migrationRequestExists(uint256 _certificateId) private view returns (bool) {
bool exists = false;

for (uint i = 1; i <= _requestMigrateToPublicNonce; i++) {
for (uint256 i = 1; i <= _requestMigrateToPublicNonce; i++) {
if (_requestMigrateToPublicStorage[i].certificateId == _certificateId) {
exists = true;
return exists;
Expand Down
Loading