Commit ae766aea authored by Bitcoin Please's avatar Bitcoin Please
Browse files

Updated Mecenas Oracle contract to a working MVP.

parent e1fd49b3
pragma cashscript ^0.4.0;
/**
* Mecenas Oracle (Fixed Block)
* Mecenas Oracle (v1 - Fixed Blocks)
*
* This contract enforces a specific market price for payouts to the
* This contract enforces a fiat market price for daily payouts to the
* contract's receipient.
*
* A minimum block is provided to ensure that the oracle price
* recipient : party whom will will receive the payouts
* funder : party whom is pledging the funding for the payouts
* oraclePk : public key for the price oracle
* minValidBlock : minimum valid block (signature & message)
* monthlyPledgeAmt : value of monthly budget (in USD cents) eg. 1,337 = $13.37
*
* A message with a block number and price from after the
* current block `tx.time` is required.
* NOTE: A minimum valid block is required to ensure the oracle's price
* signatures will invalidate each day, after the payout is made
* and a new UTXO is generated.
*
* recipient : party whom will will receive the payouts
* funder : party whom is pledging the funding for payouts
* pledgeAmt : value of each payout (in USD cents) eg. 1,337 = $13.37
* (NOTE: budgets are monthly, however payouts are daily)
* oraclePk : the public key for the price oracle
* NOTE: Although the pledged budget is set as a monthly value by the
* contract's funder, payouts are made daily to contract's receipient.
*
* eg. February payouts are 1/28 or 1/29 the monthly pledge amount
* June payouts are 1/30 the monthly pledge amount
* December payouts are 1/31 the monthly pledge amount
*/
contract MecenasOracleFixed(
contract MecenasOracle(
bytes20 recipient,
bytes20 funder,
bytes20 oracle,
int pledgeAmt,
int startingBlockHeight,
pubkey oraclePk
pubkey oraclePk,
int minValidBlock,
int monthlyPledgeAmt,
) {
/**
* Payout
......@@ -44,80 +49,30 @@ contract MecenasOracleFixed(
/* Validate oracle's (data) signature. */
require(checkDataSig(oracleSig, oracleMsg, oraclePk));
/* Validate that the UTXO is at least 30 hours old. */
// NOTE: This is notably longer than the Oracle Payout method
// below; to permit front-running and prevent contract abuse
// by bad actors.
// REMOVED FOR DEVELOPMENT PURPOSES ONLY
require(tx.age >= 30 hours);
/* Set oracle-defined block height. */
int oracleBlockHeight = int(oracleMsg.split(4)[0]);
/* Validate minimum valid block height. */
require(tx.time >= oracleBlockHeight);
/* Validate minimum valid block height is greater than starting block height. */
// NOTE: Oracle prices preceding contract creation are invalid.
require(oracleBlockHeight >= startingBlockHeight);
/* Set oracle-defined pledge amount. */
int oraclePledgeAmt = int(oracleMsg.split(4)[1].split(4)[0]);
/* Validate pledge amount. */
require(oraclePledgeAmt == pledgeAmt);
/* Set oracle-defined payout amount. */
int oraclePayoutAmt = int(oracleMsg.split(8)[1]);
/* Set (hardcoded) miner fee. */
int minerFee = 1000;
/* Retrieve the coin's value and cast it to an integer. */
int coinValue = int(bytes(tx.value));
/* Create an Output that sends the pledge amount to the recipient. */
bytes34 payeeOutput = new OutputP2PKH(bytes8(oraclePayoutAmt), recipient);
/* Calculate the coin remainder. */
bytes8 remainder = bytes8(coinValue - oraclePayoutAmt - minerFee);
/* Create an Output that sends the remainder back to the contract. */
bytes32 contractOutput = new OutputP2SH(remainder, hash160(tx.bytecode));
/* Enforce that these are the only outputs for the current transaction. */
require(hash256(payeeOutput + contractOutput) == tx.hashOutputs);
}
/**
* Oracle Payout
*
* Identical to the `payout` method above, however, we remove the
* retriction on `tx.age` to permit front-running by the Oracle.
*
* Due to the current restrictions of CashScript, we are unable to expire
* Oracle signatures, which allows them to be re-used. By replaying "old"
* signatures, it is possible to abuse of the price mechanism of the
* contract by bad actors.
*
* pk : public key of the oracle
* s : (transaction) signature of the oracle
* oracleSig : (data / message) signature of the oracle
* oracleMsg : payout authorization message from the oracle
*/
function oraclePayout(pubkey pk, sig s, datasig oracleSig, bytes oracleMsg) {
/* Validate oracle's public key. */
require(hash160(pk) == oracle);
/* Validate oracle's (transaction) signature. */
require(checkSig(s, pk));
/* Validate oracle's (data / message) signature. */
require(checkDataSig(oracleSig, oracleMsg, oraclePk));
/* Validate that the UTXO is at least 24 hours old. */
// REMOVED FOR DEVELOPMENT PURPOSES ONLY
require(tx.age >= 24 hours);
/**
* Validate that the coin is at least 24 hours old.
*
* NOTE: The coin's spendable time restriction is delayed by 3 hours
* if the caller is NOT the Oracle Bot.
*
* This allows front-running by the platform's Oracle Bot, to
* prevent (or at least deter) the contract's abuse by
* "bad actors" whom may choose to gain advantage by using a
* valid signed message with an "optimal" exchange rate
* from within the past 24 hour payout period.
*
* TODO: In v2 of this contract, it is planned to use a "streaming"
* payout system. This will employ the use of `tx.locktime`
* which should deter the advantage gained by using "expired"
* Oracle signatures, as that would reduce the payout amount.
*/
if (pk == oraclePk) {
/* require(tx.age >= 144); */
require(tx.age >= 0);
} else {
/* require(tx.age >= 162); */
require(tx.age >= 1);
}
/* Set oracle-defined block height. */
int oracleBlockHeight = int(oracleMsg.split(4)[0]);
......@@ -127,19 +82,19 @@ contract MecenasOracleFixed(
/* Validate minimum valid block height is greater than starting block height. */
// NOTE: Oracle prices preceding contract creation are invalid.
require(oracleBlockHeight >= startingBlockHeight);
require(oracleBlockHeight >= minValidBlock);
/* Set oracle-defined pledge amount. */
int oraclePledgeAmt = int(oracleMsg.split(4)[1].split(4)[0]);
/* Validate pledge amount. */
require(oraclePledgeAmt == pledgeAmt);
require(oraclePledgeAmt == monthlyPledgeAmt);
/* Set oracle-defined payout amount. */
int oraclePayoutAmt = int(oracleMsg.split(8)[1]);
/* Set (hardcoded) miner fee. */
int minerFee = 1000;
int minerFee = 1337;
/* Retrieve the coin's value and cast it to an integer. */
int coinValue = int(bytes(tx.value));
......@@ -160,7 +115,7 @@ contract MecenasOracleFixed(
/**
* Reclaim
*
* Allows the funder to AT ANYTIME reclaim their remaining pledge(s).
* Allows the funder to at ANYTIME reclaim their remaining pledge balance.
*
* NOTE: This method is NOT dependent on the operation of the Oracle.
*/
......
pragma cashscript ^0.4.0;
/**
* Mecenas Oracle (Streaming Blocks)
* Mecenas Oracle (v2 - Streaming Blocks)
*
* This contract enforces a specific market price for payouts to the
* contract's receipient.
......@@ -22,7 +22,7 @@ pragma cashscript ^0.4.0;
* oraclePk : the public key for the price oracle
* creation : the creation block height of this contract
*/
contract MecenasOracleStream(
contract MecenasOracle(
bytes20 recipient,
bytes20 funder,
int pledgeAmt,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment