Skip to content

Commit

Permalink
adding escrow for nfts
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsmkl committed Jan 27, 2022
1 parent 1173585 commit cefa625
Show file tree
Hide file tree
Showing 4 changed files with 415 additions and 227 deletions.
142 changes: 142 additions & 0 deletions contracts/conditions/NFTs/NFT721MarkedLockCondition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
pragma solidity ^0.8.0;
// Copyright 2020 Keyko GmbH.
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0


import '../Condition.sol';
import './INFTLock.sol';
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol';

/**
* @title NFT (ERC-721) Lock Condition
* @author Keyko
*
* @dev Implementation of the NFT Lock Condition for ERC-721 based NFTs
*/
contract NFT721LockCondition is Condition, ReentrancyGuardUpgradeable, IERC721ReceiverUpgradeable {

bytes32 constant public CONDITION_TYPE = keccak256('NFT721LockCondition');

event Fulfilled(
bytes32 indexed _agreementId,
bytes32 indexed _did,
address indexed _lockAddress,
bytes32 _conditionId,
uint256 _amount,
address _receiver,
address _nftContractAddress
);

/**
* @notice initialize init the contract with the following parameters
* @dev this function is called only once during the contract
* initialization.
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
*/
function initialize(
address _owner,
address _conditionStoreManagerAddress
)
external
initializer()
{
require(
_conditionStoreManagerAddress != address(0),
'Invalid address'
);
OwnableUpgradeable.__Ownable_init();
transferOwnership(_owner);
conditionStoreManager = ConditionStoreManager(
_conditionStoreManagerAddress
);
}

/**
* @notice hashValues generates the hash of condition inputs
* with the following parameters
* @param _did the DID of the asset with NFTs attached to lock
* @param _lockAddress the contract address where the NFT will be locked
* @param _amount is the amount of the locked tokens
* @param _nftContractAddress Is the address of the NFT (ERC-721) contract to use
* @return bytes32 hash of all these values
*/
function hashValues(
bytes32 _did,
address _lockAddress,
uint256 _amount,
address _receiver,
address _nftContractAddress
)
public
pure
returns (bytes32)
{
return keccak256(abi.encode(_did, _lockAddress, _amount, _receiver, _nftContractAddress));
}

/**
* @notice fulfill the transfer NFT condition
* @dev Fulfill method lock a NFT into the `_lockAddress`.
* @param _agreementId agreement identifier
* @param _did refers to the DID in which secret store will issue the decryption keys
* @param _lockAddress the contract address where the NFT will be locked
* @param _amount is the amount of the locked tokens (1)
* @param _nftContractAddress Is the address of the NFT (ERC-721) contract to use
* @return condition state (Fulfilled/Aborted)
*/
function fulfill(
bytes32 _agreementId,
bytes32 _did,
address _lockAddress,
uint256 _amount,
address _receiver,
address _nftContractAddress
)
external
nonReentrant
returns (ConditionStoreLibrary.ConditionState)
{
IERC721Upgradeable erc721 = IERC721Upgradeable(_nftContractAddress);

require(
_amount == 0 || (_amount == 1 && erc721.ownerOf(uint256(_did)) == msg.sender),
'Not enough balance'
);

if (_amount == 1) {
erc721.safeTransferFrom(msg.sender, _lockAddress, uint256(_did));
}

bytes32 _id = generateId(
_agreementId,
hashValues(_did, _lockAddress, _amount, _receiver, _nftContractAddress)
);
ConditionStoreLibrary.ConditionState state = super.fulfill(
_id,
ConditionStoreLibrary.ConditionState.Fulfilled
);

emit Fulfilled(
_agreementId,
_did,
_lockAddress,
_id,
_amount,
_receiver,
_nftContractAddress
);
return state;
}

/**
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}

}
183 changes: 183 additions & 0 deletions contracts/conditions/NFTs/NFTMarkedLockCondition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
pragma solidity ^0.8.0;
// Copyright 2020 Keyko GmbH.
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0


import '../Condition.sol';
import '../../registry/DIDRegistry.sol';
import './INFTLock.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';

/**
* @title NFT Lock Condition
* @author Keyko
*
* @dev Implementation of the NFT Lock Condition
*/
contract NFTMarkedLockCondition is Condition, ReentrancyGuardUpgradeable, IERC1155ReceiverUpgradeable {

bytes32 constant public CONDITION_TYPE = keccak256('NFTMarkedLockCondition');

bytes4 constant internal ERC1155_ACCEPTED = 0xf23a6e61; // bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))
bytes4 constant internal ERC1155_BATCH_ACCEPTED = 0xbc197c81; // bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))

event Fulfilled(
bytes32 indexed _agreementId,
bytes32 indexed _did,
address indexed _lockAddress,
bytes32 _conditionId,
uint256 _amount,
address _receiver,
address _nftContractAddress
);

/**
* @notice initialize init the contract with the following parameters
* @dev this function is called only once during the contract
* initialization.
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
*/
function initialize(
address _owner,
address _conditionStoreManagerAddress
)
external
initializer()
{
require(
_conditionStoreManagerAddress != address(0),
'Invalid address'
);
OwnableUpgradeable.__Ownable_init();
transferOwnership(_owner);
conditionStoreManager = ConditionStoreManager(
_conditionStoreManagerAddress
);

}

/**
* @notice hashValues generates the hash of condition inputs
* with the following parameters
* @param _did the DID of the asset with NFTs attached to lock
* @param _lockAddress the contract address where the NFT will be locked
* @param _amount is the amount of the locked tokens
* @param _nftContractAddress Is the address of the NFT (ERC-1155) contract to use
* @return bytes32 hash of all these values
*/
function hashValues(
bytes32 _did,
address _lockAddress,
uint256 _amount,
address _receiver,
address _nftContractAddress
)
public
pure
returns (bytes32)
{
return keccak256(
abi.encode(
_did,
_lockAddress,
_amount,
_receiver,
_nftContractAddress
)
);
}

/**
* @notice fulfill the transfer NFT condition
* @dev Fulfill method transfer a certain amount of NFTs
* to the _nftReceiver address.
* When true then fulfill the condition
* @param _agreementId agreement identifier
* @param _did refers to the DID in which secret store will issue the decryption keys
* @param _lockAddress the contract address where the NFT will be locked
* @param _amount is the amount of the locked tokens
* @param _nftContractAddress Is the address of the NFT (ERC-1155) contract to use
* @return condition state (Fulfilled/Aborted)
*/
function fulfill(
bytes32 _agreementId,
bytes32 _did,
address _lockAddress,
uint256 _amount,
address _receiver,
address _nftContractAddress
)
public
nonReentrant
returns (ConditionStoreLibrary.ConditionState)
{
IERC1155Upgradeable(_nftContractAddress).safeTransferFrom(msg.sender, _lockAddress, uint256(_did), _amount, '');

bytes32 _id = generateId(
_agreementId,
hashValues(_did, _lockAddress, _amount, _receiver, _nftContractAddress)
);
ConditionStoreLibrary.ConditionState state = super.fulfill(
_id,
ConditionStoreLibrary.ConditionState.Fulfilled
);

emit Fulfilled(
_agreementId,
_did,
_lockAddress,
_id,
_amount,
_receiver,
_nftContractAddress
);
return state;
}

// solhint-disable-next-line
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
)
external
override
pure
returns(bytes4)
{
return ERC1155_ACCEPTED;
}

function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
)
external
override
pure
returns(bytes4)
{
return ERC1155_BATCH_ACCEPTED;
}

function supportsInterface(
bytes4 interfaceId
)
external
override
pure
returns (bool)
{
return interfaceId == 0x01ffc9a7 || // ERC165
interfaceId == 0x4e2312e0; // ERC1155_ACCEPTED ^ ERC1155_BATCH_ACCEPTED;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract MultiEscrowPaymentCondition is Reward, Common, ReentrancyGuardUpgradeab

using SafeERC20Upgradeable for IERC20Upgradeable;

bytes32 constant public CONDITION_TYPE = keccak256('EscrowPayment');
bytes32 constant public CONDITION_TYPE = keccak256('MultiEscrowPayment');

event Fulfilled(
bytes32 indexed _agreementId,
Expand Down

0 comments on commit cefa625

Please sign in to comment.