Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

NFT sketching #366

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions implementation/contracts/deposit/DepositRedemption.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ library DepositRedemption {
bytes8 _outputValueBytes,
bytes20 _requesterPKH
) public {
if(_d.isLocked()) {
require(msg.sender == _d.beneficiary());
}
require(_d.inRedeemableState(), "Redemption only available from Active or Courtesy state");
require(_requesterPKH != bytes20(0), "cannot send value to zero pkh");

Expand Down
3 changes: 3 additions & 0 deletions implementation/contracts/deposit/DepositUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ library DepositUtils {
/// @dev Holds a timestamp from the moment when the transaction digest
/// was approved for signing
mapping (bytes32 => uint256) approvedDigests;

// Stateful locking mechanism
uint drawn; // amount of tbtc drawn from deposit
}

/// @notice Gets the current block difficulty
Expand Down
115 changes: 115 additions & 0 deletions implementation/contracts/system/VendingMachine.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import "./DepositOwnerToken.sol";

contract VendingMachine {
// The volume of TBTC yet to pass the qualifier.
uint public unqualifiedVolume = 0;

// Mapping of deposit to qualification status.
mapping(uint256 => bool) qualified;

// Constants
uint256 public constant BLOCK_REWARD = 125 * 10^8; // satoshis, TODO var is constant for sake of example.

modifier onlyDepositOwner(uint256 _depositOwnerTokenId) {
require(DepositOwnerToken.ownerOf(_depositOwnerTokenId) == msg.sender);
}

// After 1 conf, the DOT token can be dispensed
function dispenseDot(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vending machine shouldn't be concerned with minting owner tokens, IMO. It should solely be charged with owner token <-> TBTC exchange.

uint256 _depositId,
bytes memory _bitcoinHeaders
) public {
require(deposit.inFundingState(), "deposit in wrong state");

// Verify minimum 1 confirmation
uint minimumDifficultyFactor = TBTCConstants.getTxProofDifficultyFactor();
uint _observedDiff = evaluateProofDifficulty(_d, _bitcoinHeaders);
require(
_observedDiff >= _reqDiff.mul(minimumDifficultyFactor),
"Insufficient accumulated difficulty in header chain"
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flow (wherever it resides) should really be “give me a proof, I pass that proof to the deposit, the deposit updates its state, I check whether the deposit's proof level is enough for me, I mint the DOT”. Deposit state should be managed entirely within the deposit, and an “active” state should be defined purely from the deposit's perspective.

In particular, consider the vending machine to be one possible consumer of deposit owner tokens. Another consumer might require more or less proof, for example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Shadowfiend, Does this suggest that each Deposit has a proof state that updates dynamically for each additional proof it receives?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as an update, Looks like dynamic proof states are not very desirable. Being qualified is a deposit state (ACTIVE) Reaching that state not via an incremental process, but with a single proof.


// Mint the DOT
DepositOwnerToken.mint(msg.sender, _depositId);
unqualifiedVolume += deposit.lotSize();

// Set deposit, active?
deposit.setActive();
}

/**
* There are two flows here:
* 1) qualify, mint tbtc, destroy dot
* 2) qualify, keep dot
*/
function qualifyDot(
uint256 _depositOwnerTokenId,
bytes memory _bitcoinHeaders,
bool mintTbtc
) public onlyDepositOwner(_depositOwnerTokenId) {
require(!qualified[_depositOwnerTokenId], "already qualified");

// Check qualification
Deposit deposit = DepositOwnerToken.getDeposit(_depositOwnerTokenId);
require(isQualified(deposit, _bitcoinHeaders), "deposit doesn't qualify for minting");

qualified[_depositOwnerTokenId] = true;
unqualifiedVolume -= deposit.lotSize();

if(mintTbtc) {
// Relinquish DOT
dotToTbtc(_depositOwnerTokenId);
} else {
// Keep DOT
}
}

function redeemTbtc(uint256 _depositId) public {
tbtcToDot();
deposit.redeem();
}


// Repay TBTC drawn and receive DOT token
function tbtcToDot(
uint256 _depositId
) public {
require(DepositOwnerToken.ownerOf(_depositOwnerTokenId) == address(this), "DOT not available for vending");

require(tbtc.burn(msg.sender, 1 tbtc));
DepositOwnerToken.transferFrom(address(this), msg.sender, _depositId);
}

// Relinquish DOT token and receive TBTC
function dotToTbtc(
uint256 _depositOwnerTokenId,
bytes memory _bitcoinHeaders
) internal onlyDepositOwner(_depositOwnerTokenId) {
require(qualified[_depositOwnerTokenId], "dot not qualified");

Deposit deposit = DepositOwnerToken.getDeposit(_depositOwnerTokenId);

require(DepositOwnerToken.transferFrom(msg.sender, _depositOwnerTokenId, this), "no permission to claim");
mintTbtc(msg.sender, deposit.lotSize());
mintBeneficiaryToken(msg.sender, deposit);
}

// Returns whether a DOT is qualified to be minted into TBTC
function isQualified(Deposit storage _d, bytes memory _bitcoinHeaders) public view {
uint minimumDifficultyFactor = TBTCConstants.getTxProofDifficultyFactor();
// The stopgate is an additional security margin, which limits the volume of TBTC minted per-block,
// as to disincentivise cross-chain miner arbitrage.
uint stopgateFactor = unqualifiedVolume / BLOCK_REWARD;

// TODO modify evaluateProofDifficulty
uint _observedDiff = evaluateProofDifficulty(_d, _bitcoinHeaders);

// qualifier = 6 + n
// where 6 is the minimum number of confs to mint tbtc and
// n is the security margin (stopgate) that fluctuates according to opened deposit volume
require(
_observedDiff >= _reqDiff.mul(minimumDifficultyFactor + stopgateFactor),
"Insufficient accumulated difficulty in header chain"
);
}
}