merge lastest jl-dev branch

This commit is contained in:
Alrighttt
2018-09-29 15:59:47 +00:00
34 changed files with 2695 additions and 384 deletions

12
resolve.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
for f in $(git diff --name-only --diff-filter=U | cat); do
echo "Resolve conflict in $f ..."
git checkout --theirs $f
done
for f in $(git diff --name-only --diff-filter=U | cat); do
echo "Adding file $f ..."
git add $f
done

2
src/ac/mgnx Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6

2
src/ac/pirate Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6

View File

@@ -39,3 +39,5 @@ echo $pubkey
~/VerusCoin/src/komodod -pubkey=$pubkey -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 &
./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 &
./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 &
./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225 &
./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 &

View File

@@ -447,7 +447,51 @@ WARNING: there is an attack vector that precludes betting any large amounts, it
In order to mitigate this, the disclosure of the house entropy needs to be delayed beyond a reasonable reorg depth (notarization). It is recommended for production dice game with significant amounts of money to use such a delayed disclosure method.
Chapter 10 - lotto example
Chapter 10 - channels example
It might be hard to believe, but channels CC implements an instant payment mechanism that is secured by dPoW in a way that is backward compatible with the existing wallets, explorers, etc. and channels CC does not require both nodes to be online. Its usecases are all the usecases for Lightning Network, it is just more secure, less expensive and backward compatible! The one aspect which some might consider a downside (and others another benefit) is that all payments are onchain. This means it would increase blockchain size, but the idea is for channels CC to be used on blockchains with relatively lower value coins, so a txfee of 0.0001 is not anything significant.
Warning: very confusing blockchain reorganization issues described below. Will be confusing to most people
From a distance, the blockchain is a chain of blocks. One block after the next, each referencing all the prior blocks. Each block containing a group of transactions. Prior to getting into a block, the transactions are broadcast to the network and if it is valid, it enters the memory pool. Each miner then constructs a valid block from these memory pool transactions and when a transaction gets mined (confirmed), it is removed from the memory pool.
That is the simple version!
The reality is quite a bit more complex, but the critical aspect is that the blockchain can (and is) reorganized as part of the expected protocol. This can happen even when there is no 51% attack happening and it is important to understand this process in detail, so here goes.
What happens if two miners find a valid block at the same time? In this case the "same time" means within the time it takes for a block to propagate to the network. When a miner finds a new block, it is broadcast to the network and nodes update and start waiting for the next block. When there are two different (and valid) blocks propagating at the same time, some nodes update with one of the blocks and some the other, lets call it blockA and blockB. Now the nodes will know about both blockA and blockB, but some will consider blockA to be the chaintip and others will consider blockB to be the chaintip.
This is where it gets confusing. Which is the correct chaintip (latest block?). It turns out that both blockA and blockB are valid at this moment in time. So there are actuall two blockchains. We have what is called a small fork! Now dont worry, the protocol will help us converge to a single chain, but in order to do that, we need the next block.
Some miners will be mining from blockA and others from blockB. In most all cases, when the next block is found, it wont be at the "same time" again. So we will end up with a chain that is blockA+blockA2 or blockB+blockB2. Here comes the small reorg! Let's assuming blockA2 was found before blockB2, so that means all nodes that had blockB as the chaintip now see a longer chain blockA+blockA2, which trumps blockB. When that happens, it reorgs the chain so it is on blockA+blockA2. To do this properly, all the transactions that were in blockB are put back into the mempool and blockA is added, then blockA2.
Of course, when blockB2 arrives, the nodes see it but blockB+blockB2 is the same length as blockA+blockA2, so no reorg happens. Since we postulated that blockAs arrived "before" blockB2, that means all nodes are on the same chaintip, including all the miners and the next block found would be blockA3, without any complications.
Believe it or not, this sort of thing is happening all the time, one all blockchains. The chaintip is a volatile thing and that is why more than one confirmation is needed to avoid the small reorgs invalidating blockhash. However, it is possible for more than just the blockhash to change. When the reorg happens, all the transactions in the block are put back into the mempool and then the new blocks are processed in order. So what happens if one of the inputs to a transaction that happened in blockB, gets spent in blockA2? Based on random utxo allocation by wallets this is not impossible if an address has a lot of activity, but if it is part of a 51% attack, then this remote chance of an utxo being spent becomes a certainity! In fact, that is what a 51% attack is.
The attack can go much deeper than just one block. For chains that use the longest chain rule, it can go quite deep indeed. So as all the reorged transactions are put back into the mempool, we feel good that it will get confirmed again. Unfortunately, there is no enforcement of a miner needing to mine any specific transaction in the mempool. And the 51% attacker is intent on mining the transaction that spends an already spent utxo in the reorganized chain. it is called a double spend, but in the reorganized chain, it is spent only once. So it is a bit of a misnomer.
The important thing to understand is that if any transaction has inputs that are signed by a node, it is possible when the chain reorganizes for that transaction to become invalid. This is why dPoW is important as it doesnt strictly use the longest chain rule, but rather the longest notarized chain rule. Once a block is notarized, then it will refuse to reorganize that block (or any block before). So the risk is still there, but only until a notarization. Please see more detailed information about dPoW <here>.
Given the above, if you are wondering how can it be possible to have a mempool payment be secured by dPoW. Since it is explained how the reorgs can make valid transactions disappear, it seems unlikely any such solution is possible. However, the CC is very powerful and it can make unlikely things possible.
The following describes how.
We know that any payment that is utxo based can be invalidated via 51% attack, or even an unlikely but not impossible random utxo allocation from a busy wallet. Which means the payment cant be via a utxo. Since the CC system is utxo based, you might think that it means CC cant solve this. However, CC is very powerful and can implement payments that are not utxo based. But before this non-utxo payment method is explained, first we need to solve the mechanics of payment.
At a high level, we want to lock funds into a channel, have this lock notarized so it cant be reorganized. Then payments can unlock funds. Additionally, if we are restricting the payment to just one destination, we also need a way for the sender to reclaim the unused funds. So there needs a way for a close channel notification, which when notarized allows the sender to reclaim all funds. After the channel close is notarized, then the only action possible should be a reclaim of sender funds.
We need to assume that any payment, channel close, reclaim can be reorganized until it is notarized so great care needs to be made that a payment that is made will always be valid. With some allowances for blocks after a channelclose is notarized, we can protect the payments using the logic of "stop accepting payments after a channelclose is seen". It might be that a full notarization of wait time after the channelclose is notarized is needed to provide sufficient time for all the payments to be reprocessed.
Now we can finally describe the requirements for the CC. The locked funds need to be able to be spent by either the sender or receiver, the former only after sufficient time after a channelclose and the latter only after a payment is seen (not just confirmed, but just seeing it should be enough). The protection from reorgs is that the payment itself reveals a secret that is needed for the payment and only the secret would be needed, so it wont matter what utxo is used. To lock funds into a CC address that can handle this we need a 1of2 CC address, which can accept a signature from either of two pubkeys. The additional CC constraints would be enforced to make sure payments are made until the channel is closed.
A hashchain has the nice property of being able to encode a lot of secrets with a single hash. You can hash the hash, over and over and the final hash is the public value. By revealing the next to last hash, it can be verified that it hashes to the final hash. There is a restriction that a hashchain needs to be of reasonable maximum depth, say 1000. That means each iteration of the hashchain that is revealed is worth 1/1000th the total channelfunds. In fact, if the 500th hash value is revealed, half the channelfunds are released. this allows 1/1000th resolution that can be released with a single hash value.
Now we can make the payment based on the hashvalue revealed at a specified depth before the prior released hashchain value. Both the sender and receiver can make a payment to the destination by attaching a hashchain secret. This means even if the sender's payment is reorganized, if the destination has the revealed secret, a replacement payment can be made that is valid. If the destination account isnt monitoring the blockchain, then it wont see the revealed secret, but in this case there shouldnt be value released for the payments that are reorganized. So it would be a case of no harm, no foul. In any event, all the payments end up verifiable on the blockchain to provide verifiability.
Payments at the speed of the mempool, protected by dPoW!
<details of rpc calls, vin/vout allocations, etc>
Chapter 11 - oracles example
Oracles CC is an example where it ended up being simpler than I first expected, but at the same time a lot more powerful. It is one of the smaller CC, but it enables creation of an arbitrary number of data markets, in a performant way.
@@ -582,6 +626,39 @@ Conclusion
I hope this document has helped you understand what a Komodo utxo based CC contract is and how it is different from the other smart contracts. If you are now able to dive into the cc directory and start making your own CC contract, then I am very happy!
gateways CC
gateways CC is the first CC that combines multiple CC into a single one. In order to achieve its goals, both the assets CC and the oracles CC is used, in addition to a dapp that issues regular transactions. This general approach can be used to solve quite a few different use cases, so it is important to understand how a multi-CC solution is put together. There are some tricky issues that only arise when using more than one CC at a time.
Before the implementation details, first lets understand what the gateways CC does. At a high level it is similar to the old multigateway (from NXT AE 2014), but with improvements. The basic idea is to tokenize other crypto coins (like BTC) and then use the assets CC to transact/swap against the tokenized crypto. By enforcing a 1:1 peg between a specific token and BTC and an automated deposit/withdraw mechanism, it is possible to transact in the virtual BTC without the delay or expensive txfees. Then anybody that ends up having any of the BTC token would be able to withdraw actual BTC by redeeming the token.
BTC -> deposit to special address -> receive token that represents BTC onchain
do onchain transactions with the BTC token
anybody who obtains the BTC token can redeem the token and get actual BTC in the withdraw address
By bringing the operations onchain, it avoids the need for crosschain complications for each trade. The crosschain does still have to happen on the deposit and withdraw, but that is all. There is just one aspect that makes it not fully decentralized, which is the reliance on MofN multisig. However, with N trusted community members and a reasonable M value, it is not expected to be a big barrier. Since all operations are automated, the only trust needed is that M of the N multisig signers are running their nodes with the gateways dapp active and also that M of them wont collude to steal the funds locked in the multisig. In three years of operations, the MGW multigateway didnt have any incident of multisig signer misbehavior and it was only 2of3 multisig.
How can the gatewaysCC work? First, it needs a dedicated token that can be used to represent the external crypto coin. In order to avoid any issues with misplaced tokens, it is simplest to require that 100% of all the tokens are all locked in the gatewaysCC address. We want to make it so that the only way the tokens can be released from the locked address is when a verified deposit is made. So, we also need a deposit address, which means there needs to be a set of pubkeys that control the deposit address. It turns out, we also need to post merkleroot data from the external coin so that the information is onchain to be able to validate the external deposit. Since we are already trusting the deposit address signers to safekeep the external coins via MofN multisig, trusting them to post the merkleroots doesnt increase the trust footprint needed.
Now we have all the ingredients needed, a dedicated token, a set of multisig pubkeys and an oracle for merkleroots.
gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)
With a gatewaysbind, a new gateway is defined. the pubkeys are for the custodians of the multisig funds and they also need to be posting merkleroots to the chain, so the oracle needs to be setup and funded and each of the signers needs to run the oraclefeed dapp. That posts each new merkleroot via oraclesdata and also responds to withdraw requests.
The MofN pubkeys generates a deposit address and when funds are sent to that address along with a small amount to the claim address. With the txid from this external coin, along with the txproof and the rawtransaction, all is submitted with a gatewaysdeposit. This adds a special baton output which is a gateways CC output to invoke gateways validation and also prevents double claims by using the unspent status of the baton.
gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount
gatewaysclaim bindtxid coin deposittxid destpub amount
Once the gatewaysdeposit is validated, it can be claimed and now the token is sent to the claim address. A 1:1 pegging of the external crypto to the token is established. And as long as one of the deposit address signers is running the oraclefeed, then the deposit/claim process is fully automatic and under the control of the depositor. Nothing needs to be signed by any other party! Also by using the utxo from the deposittxid, double claims are prevented.
On the withdraw side, the tokens are sent back to the address where the tokens are locked and this needs to create a redemption right that can only be used once.
gatewayswithdraw bindtxid coin withdrawpub amount
And with a bit more magic in the oraclefeed, this is achieved. To be continued...

View File

@@ -18,10 +18,19 @@
#define CC_GATEWAYS_H
#include "CCinclude.h"
#include "../merkleblock.h"
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount);
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin);
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid);
std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr);
// CCcustom
UniValue GatewaysInfo();
UniValue GatewaysInfo(uint256 bindtxid);
UniValue GatewaysList();
#endif

View File

@@ -19,8 +19,6 @@
#include "CCinclude.h"
#define ORACLES_MAXPROVIDERS 64
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format);
std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee);

View File

@@ -22,6 +22,13 @@
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
// CCcustom
UniValue PricesInfo();
UniValue PricesList();
UniValue PricesInfo(uint256 fundingtxid);
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid);
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys);
std::string PricesAddFunding(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount);
std::string PricesBet(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount,int32_t leverage);
std::string PricesFinish(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,uint256 bettxid);
#endif

View File

@@ -54,6 +54,8 @@ UniValue AssetInfo(uint256 tokenid);
UniValue AssetList();
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description);
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total);
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode);
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal);
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid);
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount);

View File

@@ -354,7 +354,7 @@ int64_t IsAssetvout(int64_t &price,std::vector<uint8_t> &origpubkey,const CTrans
return(0);
if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
{
fprintf(stderr,"null decodeopret\n");
fprintf(stderr,"null decodeopret v.%d\n",v);
return(0);
}
else if ( funcid == 'c' )
@@ -367,7 +367,10 @@ int64_t IsAssetvout(int64_t &price,std::vector<uint8_t> &origpubkey,const CTrans
else if ( funcid != 'E' )
{
if ( assetid == refassetid )
{
//fprintf(stderr,"returning %.8f\n",(double)nValue/COIN);
return(nValue);
}
}
else if ( funcid == 'E' )
{
@@ -447,7 +450,7 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp
bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
CTransaction vinTx; uint256 hashBlock,id,id2; int32_t i,flag,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
numvins = tx.vin.size();
numvouts = tx.vout.size();
inputs = outputs = 0;
@@ -465,8 +468,20 @@ bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti
fprintf(stderr,"vin%d %llu, ",i,(long long)assetoshis);
inputs += assetoshis;
}
else
{
if ( vinTx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 && DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
{
assetoshis = vinTx.vout[i].nValue;
fprintf(stderr,"vin%d %llu special case, ",i,(long long)assetoshis);
inputs += assetoshis;
}
}
}
}
if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
flag = 1;
else flag = 0;
for (i=0; i<numvouts; i++)
{
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
@@ -474,6 +489,12 @@ bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti
fprintf(stderr,"vout%d %llu, ",i,(long long)assetoshis);
outputs += assetoshis;
}
else if ( flag != 0 && tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
assetoshis = tx.vout[i].nValue;
fprintf(stderr,"vout%d %llu special case, ",i,(long long)assetoshis);
outputs += assetoshis;
}
}
if ( inputs != outputs )
{

View File

@@ -17,10 +17,11 @@
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -32,6 +33,10 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
continue;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
fprintf(stderr,"check %s %.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
if ( (nValue= IsAssetvout(price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
@@ -223,21 +228,47 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
for (i=0; i<n; i++)
total += amounts[i];*/
mask = ~((1LL << mtx.vin.size()) - 1);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{
if ( inputs > total )
CCchange = (inputs - total);
//for (i=0; i<n; i++)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey)));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{
if ( inputs > total )
CCchange = (inputs - total);
//for (i=0; i<n; i++)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey)));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
}
return("");
}
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
{
CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
if ( total < 0 )
{
fprintf(stderr,"negative total %lld\n",(long long)total);
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{
if ( inputs > total )
CCchange = (inputs - total);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
mtx.vout.push_back(MakeCC1vout(evalcode,total,pubkey2pk(destpubkey)));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
}
return("");
}
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
{
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description;

View File

@@ -67,15 +67,22 @@ struct CC_utxo
struct CCcontract_info
{
uint256 prevtxid;
char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64];
uint8_t CCpriv[32],unspendablepriv2[32];
CPubKey unspendablepk2;
char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64];
uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32];
CPubKey unspendablepk2,unspendablepk3;
bool (*validate)(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool (*ismyvin)(CScript const& scriptSig);
uint8_t evalcode,didinit;
uint8_t evalcode,evalcode2,evalcode3,didinit;
};
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
struct oracleprice_info
{
CPubKey pk;
std::vector <uint8_t> data;
int32_t height;
};
#ifdef ENABLE_WALLET
extern CWallet* pwalletMain;
#endif
@@ -92,8 +99,21 @@ bool mySendrawtransaction(std::string res);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
int64_t CCaddress_balance(char *coinaddr);
CPubKey CCtxidaddr(char *txidaddr,uint256 txid);
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vector<struct oracle_merklepair>publishers);
uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey);
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey);
// CCcustom
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
@@ -106,6 +126,8 @@ CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk);
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2);
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
CC* GetCryptoCondition(CScript const& scriptSig);
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
bool IsCCInput(CScript const& scriptSig);
int32_t unstringbits(char *buf,uint64_t bits);
uint64_t stringbits(char *str);
@@ -114,6 +136,10 @@ char *uint256_str(char *dest,uint256 txid);
char *pubkey33_str(char *dest,uint8_t *pubkey33);
uint256 Parseuint256(char *hexstr);
CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
int64_t CCfullsupply(uint256 tokenid);
int64_t CCtoken_balance(char *destaddr,uint256 tokenid);
int64_t CCtoken_balance2(char *destaddr,uint256 tokenid);
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk);
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk);
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2);
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue);

View File

@@ -41,7 +41,7 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
{
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*cond; CPubKey unspendablepk;
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk;
n = mtx.vout.size();
for (i=0; i<n; i++)
{
@@ -124,9 +124,17 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
//fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if ( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->evalcode,cp->unspendablepk2);
othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
cond = othercond2;
}
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
{
//fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
privkey = cp->unspendablepriv3;
if ( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
cond = othercond3;
}
else
{
fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr);
@@ -155,6 +163,10 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
cc_free(mycond);
if ( othercond != 0 )
cc_free(othercond);
if ( othercond2 != 0 )
cc_free(othercond2);
if ( othercond3 != 0 )
cc_free(othercond3);
std::string strHex = EncodeHexTx(mtx);
if ( strHex.size() > 0 )
return(strHex);
@@ -212,6 +224,50 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
return(0);
}
int64_t CCaddress_balance(char *coinaddr)
{
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
sum += it->second.satoshis;
}
return(sum);
}
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
{
return(tx.vout[0].nValue);
}
}
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
{
sum += it->second.satoshis;
}
}
}
return(sum);
}
int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct CC_utxo utxos[],int32_t numunspents,int64_t value)
{
int32_t i,abovei,belowi; int64_t above,below,gap,atx_value;
@@ -301,6 +357,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
up->txid = txid;
up->nValue = out.tx->vout[out.i].nValue;
up->vout = vout;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos )
break;
}
@@ -333,12 +390,16 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
remains -= up->nValue;
utxos[ind] = utxos[--n];
memset(&utxos[n],0,sizeof(utxos[n]));
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
if ( totalinputs >= total || (i+1) >= maxinputs )
break;
}
free(utxos);
if ( totalinputs >= total )
{
//fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
return(totalinputs);
}
#endif
return(0);
}

View File

@@ -63,6 +63,7 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
CTxOut vout;
CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
vout = CTxOut(nValue,CCPubKey(payoutCond));
fprintf(stderr,"payoutCond: %s\n",cc_conditionToJSONString(payoutCond));
cc_free(payoutCond);
return(vout);
}
@@ -169,6 +170,22 @@ CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
return(pk);
}
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode2 = evalcode;
cp->unspendablepk2 = pk;
memcpy(cp->unspendablepriv2,priv,32);
strcpy(cp->unspendableaddr2,coinaddr);
}
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode3 = evalcode;
cp->unspendablepk3 = pk;
memcpy(cp->unspendablepriv3,priv,32);
strcpy(cp->unspendableaddr3,coinaddr);
}
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
{
CTxDestination address; txnouttype whichType;
@@ -181,13 +198,29 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
return(false);
}
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
bool pubkey2addr(char *destaddr,uint8_t *pubkey33)
{
std::vector<uint8_t>pk; int32_t i;
for (i=0; i<33; i++)
pk.push_back(pubkey33[i]);
return(Getscriptaddress(destaddr,CScript() << pk << OP_CHECKSIG));
}
CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
{
uint8_t buf33[33]; CPubKey pk;
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&txid,32);
pk = buf2pk(buf33);
Getscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
return(pk);
}
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
{
CC *payoutCond;
destaddr[0] = 0;
if ( pk.size() == 0 )
pk = GetUnspendable(cp,0);
if ( (payoutCond= MakeCCcond1(cp->evalcode,pk)) != 0 )
if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 )
{
Getscriptaddress(destaddr,CCPubKey(payoutCond));
cc_free(payoutCond);
@@ -195,6 +228,14 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
return(destaddr[0] != 0);
}
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
{
destaddr[0] = 0;
if ( pk.size() == 0 )
pk = GetUnspendable(cp,0);
return(_GetCCaddress(destaddr,cp->evalcode,pk));
}
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
{
CC *payoutCond;
@@ -323,6 +364,8 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> param
//if ( txid == cp->prevtxid )
// return(true);
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
cp->evalcode2 = cp->evalcode3 = 0;
cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
if ( paramsNull.size() != 0 ) // Don't expect params
return eval->Invalid("Cannot have params");
else if ( ctx.vout.size() == 0 )

View File

@@ -167,7 +167,6 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
//vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"<assetname>":"<description>"}]
return eval->Invalid("unexpected AssetValidate for createasset");
break;
case 't': // transfer
//vin.0: normal input
//vin.1 .. vin.n-1: valid CC outputs
@@ -176,7 +175,7 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
//vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
if ( inputs == 0 )
return eval->Invalid("no asset inputs for transfer");
fprintf(stderr,"transfer validated %.8f -> %.8f\n",(double)inputs/COIN,(double)outputs/COIN);
fprintf(stderr,"transfer validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts);
break;
case 'b': // buyoffer

View File

@@ -1,24 +0,0 @@
#!/bin/bash
# SET AC
read -p "Enter AC name you use : " acname
sed -i "/#define ACNAME */c\#define ACNAME \"$acname\"" oraclefeed.c
# Set ORACLETXID
read -p "Enter your oracle TXID (Oracle should have L data type) : " oracletxid
sed -i "/#define ORACLETXID */c\#define ORACLETXID \"$oracletxid\"" oraclefeed.c
# SET PUBKEY
read -p "Enter your pubkey : " pubkey
sed -i "/#define MYPUBKEY */c\#define MYPUBKEY \"$pubkey\"" oraclefeed.c
# COMPILATION
echo "Great, compiling !"
gcc oraclefeed.c -lm -o oracle_dapp
mv oracle_dapp ../../oracle_dapp
echo "Oracle is ready to use !"
while true; do
read -p "Would you like to run BTCUSD oracle app? [Y/N]" yn
case $yn in
[Yy]* ) cd ../..; ./oracle_dapp; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done

View File

@@ -19,7 +19,6 @@
#include <memory.h>
#include "cJSON.c"
char hexbyte(int32_t c)
{
c &= 0xf;
@@ -309,63 +308,577 @@ uint64_t get_btcusd()
return(btcusd);
}
cJSON *get_komodocli(char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2)
char *REFCOIN_CLI;
cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
{
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,*fname = "/tmp/komodocli";
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,fname);
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256];
sprintf(fname,"/tmp/oraclefeed.%s",method);
if ( acname[0] != 0 )
{
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname);
}
else if ( strcmp(refcoin,"KMD") == 0 )
sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname);
else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
{
sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
}
system(cmdstr);
*retstrp = 0;
if ( (jsonstr= filestr(&fsize,fname)) != 0 )
{
//fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
if ( (retjson= cJSON_Parse(jsonstr)) == 0 )
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
*retstrp = jsonstr;
else free(jsonstr);
}
return(retjson);
}
void bntn()
bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
{
long fsize; int32_t i,n; cJSON *item,*retjson = 0; char cmdstr[32768],*jsonstr,*addr; double val;
if ( (jsonstr= filestr(&fsize,"bntn")) != 0 )
{
if ( (retjson= cJSON_Parse(jsonstr)) != 0 )
{
if ( (n= cJSON_GetArraySize(retjson)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(retjson,i);
if ( (addr= jstr(item,"KMD Address")) != 0 && (val= jdouble(item,"(BNTN)")) > 0 )
{
val = 1387;
if ( addr[0] == 'z' )
printf("./komodo-cli -ac_name=BNTN sendtoaddress %s %.8f\n",addr,val);
}
}
}
free_json(retjson);
}
}
}
void komodobroadcast(char *acname,cJSON *hexjson)
{
char *hexstr,*retstr; cJSON *retjson;
char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
if ( (hexstr= jstr(hexjson,"hex")) != 0 )
{
if ( (retjson= get_komodocli(&retstr,acname,"sendrawtransaction",hexstr,"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
{
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"txid.(%s)\n",retstr);
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
decode_hex(txid.bytes,32,retstr);
}
fprintf(stderr,"broadcast %s txid.(%s)\n",acname,bits256_str(str,txid));
free(retstr);
}
}
return(txid);
}
bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis)
{
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 )
{
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
decode_hex(txid.bytes,32,retstr);
}
fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
free(retstr);
}
return(txid);
}
int32_t get_coinheight(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr; int32_t height=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
{
height = jint(retjson,"blocks");
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(height);
}
bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
{
cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
memset(hash.bytes,0,sizeof(hash));
sprintf(heightstr,"%d",height);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
{
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
decode_hex(hash.bytes,32,retstr);
}
free(retstr);
}
return(hash);
}
bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash)
{
cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
{
merkleroot = jbits256(retjson,"merkleroot");
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(merkleroot);
}
int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight)
{
int32_t height = 0; char str[65];
if ( prevheight == 0 )
height = get_coinheight(refcoin,acname) - 20;
else height = prevheight + 1;
if ( height > 0 )
{
*blockhashp = get_coinblockhash(refcoin,acname,height);
if ( bits256_nonz(*blockhashp) != 0 )
{
*merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp);
if ( bits256_nonz(*merklerootp) != 0 )
return(height);
}
}
memset(blockhashp,0,sizeof(*blockhashp));
memset(merklerootp,0,sizeof(*merklerootp));
return(0);
}
cJSON *get_gatewayspending(char *refcoin,char *acname,char *oraclestxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",oraclestxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"%s get_gatewayspending.(%s) error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(0);
}
cJSON *get_rawmempool(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
{
//printf("mempool.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr);
free(retstr);
}
return(0);
}
cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
{
cJSON *retjson; char *retstr,jsonbuf[256];
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("warning: assumes %s has addressindex enabled\n",refcoin);
sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
{
//printf("addressutxos.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
free(retstr);
}
return(0);
}
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
{
cJSON *retjson; char *retstr,str[65];
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
{
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(0);
}
void importaddress(char *refcoin,char *acname,char *depositaddr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,"","true","")) != 0 )
{
printf("importaddress.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"importaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
}
cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required)
{
cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid;
*totalp = 0;
if ( (n= cJSON_GetArraySize(unspents)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(unspents,i);
satoshis = jdouble(item,"amount") * SATOSHIDEN;
txid = jbits256(item,"txid");
v = jint(item,"vout");
if ( bits256_nonz(txid) != 0 )
{
vin = cJSON_CreateObject();
jaddbits256(vin,"txid",txid);
jaddnum(vin,"vout",v);
jaddi(vins,vin);
*totalp += satoshis;
if ( (*totalp) >= required )
break;
}
}
}
return(vins);
}
char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signeraddr,char *withdrawaddr,int64_t satoshis)
{
char *retstr,*retstr2,array[128],*txstr = 0; cJSON *retjson2,*retjson,*vins,*vouts; int64_t txfee,total,change = 0;
if ( strcmp(refcoin,"BTC") == 0 )
txfee = 20000;
else txfee = 10000;
if ( satoshis < txfee )
{
printf("createmultisig satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
return(0);
}
satoshis -= txfee;
sprintf(array,"[\"%s\"]",depositaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
{
//createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 )
{
if ( total >= satoshis )
{
vouts = cJSON_CreateObject();
jaddnum(vouts,withdrawaddr,(double)satoshis/SATOSHIDEN);
if ( total > satoshis+txfee )
{
change = (total - satoshis);
jaddnum(vouts,depositaddr,(double)change/SATOSHIDEN);
}
char *argA,*argB;
argA = jprint(vins,1);
argB = jprint(vouts,1);
if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
{
printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0));
free_json(retjson2);
}
else if ( txstr == 0 )
printf("createmultisig: null txstr and JSON2\n");
free(argA);
free(argB);
}
}
}
else if ( retstr != 0 )
{
printf("createmultisig: unexpected null JSON, retstr.(%s)\n",retstr);
free(retstr);
}
else printf("createmultisig: null retstr and JSON\n");
return(txstr);
}
cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx)
{
char *retstr,*hexstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
{
if ( jint(retjson,"complete") != 0 )
return(retjson);
else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) )
{
jaddnum(retjson,"partialtx",1);
return(retjson);
}
free_json(retjson);
}
return(0);
}
char *get_gatewaysmultisig(char *refcoin,char *acname,char *bindtxidstr,char *withtxidstr,char *txidaddr)
{
char *retstr,*hexstr,*hex=0; cJSON *retjson;
if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",bindtxidstr,refcoin,withtxidstr,txidaddr)) != 0 )
{
if ( (hexstr= jstr(retjson,"hex")) != 0 )
hex = clonestr(hexstr);
free_json(retjson);
}
return(hex);
}
void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,bits256_str(str2,cointxid),"")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("error parsing gatewaysmarkdone.(%s)\n",retstr);
free(retstr);
}
}
int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr)
{
char *oracle,*retstr,*name,*deposit; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
{
if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 )
{
strcpy(depositaddr,deposit);
if ( jstr(retjson,"coin") != 0 && strcmp(jstr(retjson,"coin"),coin) == 0 && jint(retjson,"N") >= 1 )
{
*Mp = jint(retjson,"M");
*Np = jint(retjson,"N");
//printf("(%s)\n",jprint(retjson,0));
} else printf("coin.%s vs %s\n",jstr(retjson,"coin"),coin);
} else printf("%s != %s\n",oracle,oraclestr);
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("error parsing get_gatewaysinfo.(%s)\n",retstr);
free(retstr);
}
if ( *Mp <= 0 || *Np <= 0 )
return(-1);
else return(0);
}
int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr)
{
cJSON *txobj,*vouts,*vout,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numvouts,retval = 0;
if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 )
{
if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 )
{
for (i=0; i<numvouts; i++)
{
vout = jitem(vouts,i);
if ( (sobj= jobj(vout,"scriptPubKey")) != 0 )
{
if ( (addresses= jarray(&n,sobj,"addresses")) != 0 )
{
for (j=0; j<n; j++)
{
addr = jstri(addresses,j);
if ( strcmp(addr,coinaddr) == 0 )
{
//fprintf(stderr,"found %s in %s v%d\n",coinaddr,bits256_str(str,txid),i);
retval = 1;
}
}
}
}
}
}
free_json(txobj);
}
return(retval);
}
int32_t coinaddrexists(char *refcoin,char *acname,char *coinaddr)
{
cJSON *array; bits256 txid; int32_t i,n,num=0;
if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 )
{
num = cJSON_GetArraySize(array);
free_json(array);
} else return(-1);
if ( num == 0 )
{
if ( (array= get_rawmempool(refcoin,acname)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) != 0 )
{
for (i=0; i<n; i++)
{
txid = jbits256i(array,i);
if ( tx_has_voutaddress(refcoin,acname,txid,coinaddr) > 0 )
{
num = 1;
break;
}
}
}
free_json(array);
} else return(-1);
}
return(num);
}
void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
{
// check queue to prevent duplicate
// check KMD chain and mempool for txidaddr
// if txidaddr exists properly, spend the marker (txid.2)
// create withdraw tx and sign it
/// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2)
/// if not enough sigs, post partially signed to acname with marker2
// monitor marker2, for the partially signed withdraws
cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,retval,processed = 0; bits256 txid,cointxid,origtxid,zeroid; int64_t satoshis;
memset(&zeroid,0,sizeof(zeroid));
if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
if ( (pending= jarray(&n,retjson,"pending")) != 0 )
{
for (i=0; i<n; i++)
{
if ( processed != 0 ) // avoid out of utxo conditions
break;
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
//process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"}
if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
{
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && (retval= coinaddrexists("KMD",acname,txidaddr)) == 0 )
{
// this is less errors but more expensive: ./komodo-cli z_sendmany "signeraddr" '[{"address":"<txidaddr>","amount":0.0001},{"address":"<withdrawaddr>","amount":<withamount>}]'
txid = sendtoaddress("KMD",acname,txidaddr,10000);
if ( bits256_nonz(txid) != 0 && coinaddrexists("KMD",acname,txidaddr) > 0 )
{
// the actual withdraw
if ( strcmp(depositaddr,signeraddr) == 0 )
{
cointxid = sendtoaddress(refcoin,"",withdrawaddr,satoshis);
if ( bits256_nonz(cointxid) != 0 )
{
fprintf(stderr,"withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid);
processed++;
}
else
{
fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
}
}
else
{
if ( (rawtx= get_gatewaysmultisig(refcoin,acname,bindtxidstr,bits256_str(str,origtxid),txidaddr)) == 0 )
{
rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis);
}
if ( rawtx != 0 )
{
if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 )
{
if ( jint(clijson,"complete") != 0 )
{
cointxid = komodobroadcast(refcoin,"",clijson);
if ( bits256_nonz(cointxid) != 0 )
{
fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid);
}
}
else if ( jint(clijson,"partialtx") != 0 )
{
// 10000 + ith -> txidaddr
txid = komodobroadcast("KMD",acname,clijson);
fprintf(stderr,"%s M.%d of N.%d partialtx %s sent\n",refcoin,M,N,bits256_str(str,txid));
}
free_json(clijson);
}
processed++;
free(rawtx);
} else fprintf(stderr,"couldnt create msig rawtx\n");
}
}
}
else if ( retval > 0 )
{
fprintf(stderr,"already did withdraw %s %s %.8f processed\n",refcoin,withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone("KMD",acname,origtxid,refcoin,zeroid);
}
}
}
}
}
free_json(retjson);
}
}
int32_t get_oracledata(char *refcoin,char *acname,int32_t prevheight,char *hexstr,int32_t maxsize,char *format)
{
int32_t i; uint32_t height; uint64_t price; bits256 blockhash,merkleroot;
hexstr[0] = 0;
if ( format[0] == 'L' || format[0] == 'l' )
{
if ( (price= get_btcusd()) != 0 )
{
for (i=0; i<8; i++)
sprintf(&hexstr[i*2],"%02x",(uint8_t)((price >> (i*8)) & 0xff));
hexstr[16] = 0;
return(16);
}
}
else if ( strcmp(format,"Ihh") == 0 )
{
if ( (height= get_coinheader(refcoin,acname,&blockhash,&merkleroot,prevheight)) > prevheight )
{
for (i=0; i<4; i++)
sprintf(&hexstr[i*2],"%02x",(uint8_t)((height >> (i*8)) & 0xff));
for (i=31; i>=0; i--)
sprintf(&hexstr[8 + (31-i)*2],"%02x",blockhash.bytes[i]);
for (i=31; i>=0; i--)
sprintf(&hexstr[8 + 64 + (31-i)*2],"%02x",merkleroot.bytes[i]);
hexstr[8 + 64*2] = 0;
return(height);
}
}
return(0);
}
/*
@@ -390,39 +903,81 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034
*/
#define ORACLETXID "4895f631316a649e216153aee7a574bd281686265dc4e8d37597f72353facac3"
#define MYPUBKEY "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92"
#define ACNAME "ORCL"
// ./a.out AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
int32_t main(int32_t argc,char **argv)
{
cJSON *clijson,*clijson2,*regjson,*item; int32_t i,j,n; char *retstr,*retstr2,*pkstr,hexstr[64]; uint64_t price;
cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid;
if ( argc < 6 )
{
printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n");
return(-1);
}
printf("Powered by CoinDesk (%s) %.8f\n","https://www.coindesk.com/price/",dstr(get_btcusd()));
acname = argv[1];
oraclestr = argv[2];
pkstr = argv[3];
format = argv[4];
bindtxidstr = argv[5];
if ( argc > 6 )
REFCOIN_CLI = argv[6];
else REFCOIN_CLI = "./komodo-cli";
if ( strncmp(format,"Ihh",3) != 0 && format[0] != 'L' )
{
printf("only formats of L and Ihh are supported now\n");
return(-1);
}
M = N = 1;
acheight = 0;
refcoin[0] = 0;
while ( 1 )
{
retstr = 0;
if ( (price= get_btcusd()) != 0 && (clijson= get_komodocli(&retstr,ACNAME,"oraclesinfo",ORACLETXID,"","")) != 0 )
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
{
if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 )
{
strcpy(refcoin,jstr(clijson,"name"));
if ( strcmp("KMD",refcoin) != 0 && argc != 7 )
{
printf("need to specify path to refcoin's cli as last argv\n");
exit(0);
}
if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr) < 0 )
{
printf("cant find bindtxid.(%s)\n",bindtxidstr);
exit(0);
}
importaddress(refcoin,"",depositaddr);
printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N);
}
if ( (regjson= jarray(&n,clijson,"registered")) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(regjson,i);
if ( (pkstr= jstr(item,"publisher")) != 0 && strcmp(pkstr,MYPUBKEY) == 0 )
if ( (pubstr= jstr(item,"publisher")) != 0 && strcmp(pkstr,pubstr) == 0 )
{
for (j=0; j<8; j++)
sprintf(&hexstr[j*2],"%02x",(uint8_t)((price >> (j*8)) & 0xff));
hexstr[16] = 0;
if ( (clijson2= get_komodocli(&retstr2,ACNAME,"oraclesdata",ORACLETXID,hexstr,"")) != 0 )
if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
{
//printf("data.(%s)\n",jprint(clijson2,0));
komodobroadcast(ACNAME,clijson2);
free_json(clijson2);
}
else if ( retstr2 != 0 )
{
printf("error parsing oraclesdata.(%s)\n",retstr2);
free(retstr2);
if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
{
//printf("data.(%s)\n",jprint(clijson2,0));
txid = komodobroadcast("KMD",acname,clijson2);
if ( bits256_nonz(txid) != 0 )
{
prevheight = height;
acheight = get_coinheight(refcoin,"");
printf("%s ht.%d <- %s\n",refcoin,height,hexstr);
update_gatewayspending(refcoin,acname,bindtxidstr,M,N);
}
free_json(clijson2);
}
else if ( retstr2 != 0 )
{
printf("error parsing oraclesdata.(%s)\n",retstr2);
free(retstr2);
}
}
break;
}
@@ -435,7 +990,8 @@ int32_t main(int32_t argc,char **argv)
printf("got json parse error.(%s)\n",retstr);
free(retstr);
}
sleep(60);
sleep(10);
// best check is for txid to not be in mempool, ie confirmed
}
return(0);
}

View File

@@ -15,16 +15,192 @@
#include "CCGateways.h"
/*
prevent duplicate bindtxid via mempool scan
wait for notarization for oraclefeed and validation of gatewaysdeposit
debug multisig and do partial signing
validation
string oracles
*/
/*
Uses MofN CC's normal msig handling to create automated deposits -> token issuing. And partial signing by the selected pubkeys for releasing the funds. A user would be able to select which pubkeys to use to construct the automated deposit/redeem multisigs.
the potential pubkeys to be used would be based on active oracle data providers with recent activity.
bind asset <-> KMD gateway deposit address
KMD deposit -> globally spendable marker utxo
spend marker utxo and spend linked/locked asset to user's CC address
*/
redeem -> asset to global CC address with withdraw address -> gateway spendable marker utxo
spend market utxo and withdraw from gateway deposit address
rpc calls:
GatewayList
GatewayInfo bindtxid
GatewayBind coin tokenid M N pubkey(s)
external: deposit to depositaddr with claimpubkey
GatewayDeposit coin tokenid external.deposittxid -> markertxid
GatewayClaim coin tokenid external.deposittxid markertxid -> spend marker and deposit asset
GatewayWithdraw coin tokenid withdrawaddr
external: do withdraw to withdrawaddr and spend marker, support for partial signatures and autocomplete
deposit addr can be 1 to MofN pubkeys
1:1 gateway with native coin
In order to create a new gateway it is necessary to follow some strict steps.
1. create a token with the max possible supply that will be issued
2. transfer 100% of them to the gateways CC's global pubkey's asset CC address. (yes it is a bit confusing)
3. create an oracle with the identical name, ie. KMD and format must start with Ihh (height, blockhash, merkleroot)
4. register a publisher and fund it with a subscribe. there will be a special client app that will automatically publish the merkleroots.
5. Now a gatewaysbind can bind an external coin to an asset, along with the oracle for the merkleroots. the txid from the bind is used in most of the other gateways CC calls
usage:
./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a
transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb
./c tokentransfer a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 100000000000000
2206fc39c0f384ca79819eb491ddbf889642cbfe4d0796bb6a8010ed53064a56
./c oraclescreate KMD blockheaders Ihh
1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808
./c oraclesregister 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 1000000
83b59eac238cbe54616ee13b2fdde85a48ec869295eb04051671a1727c9eb402
./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000
f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102
gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)
./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
./c gatewaysinfo e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
{
"result": "success",
"name": "Gateways",
"pubkey": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",
"coin": "KMD",
"oracletxid": "1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808",
"taddr": 0,
"prefix": 60,
"prefix2": 85,
"deposit": "",
"tokenid": "a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a",
"totalsupply": "1000000.00000000",
"remaining": "1000000.00000000",
"issued": "0.00000000"
}
To make a gateway deposit, send the funds to the "deposit" address, along with any amount to the same pubkey address you want to get the assetized KMD to appear in.
0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 pubkey for RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha
./komodo-cli z_sendmany "<funding addr>" '[{"address":"RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha","amount":0.0001},{"address":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","amount":7.6999}]'
bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 height.1003776 merkle.90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f
./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]'
04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b
./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009
010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b
gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount
./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
-> 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6
to get the merkleroots onchain, from the multisig signers nodes run the oraclefeed program with acname oracletxid pubkey Ihh
./oraclefeed AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh
gatewaysclaim bindtxid coin deposittxid destpub amount
./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
now the asset is in the pubkey's asset address!
it can be used, traded freely and any node who has the asset can do a gatewayswithdraw
gatewayswithdraw bindtxid coin withdrawpub amount
./c gatewayswithdraw e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 1
ef3cc452da006eb2edda6b6ed3d3347664be51260f3e91f59ec44ec9701367f0
Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side
gatewayspending bindtxid coin
gatewayspending will display all pending withdraws and if it is done on one of the msigpubkeys, then it will queue it for processing
./c gatewayspending e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD
Implementation Issues:
When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly.
Care must be taken so that tokens are not lost and can be converted back.
This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241
The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS.
*/
int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue)
{
char destaddr[64],str[65];
Getscriptaddress(destaddr,scriptPubKey);
fprintf(stderr,"GatewaysAddQueue: %s %s %s %.8f\n",coin.c_str(),uint256_str(str,txid),destaddr,(double)nValue/COIN);
}
// start of consensus code
CScript EncodeGatewaysBindOpRet(uint8_t funcid,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
{
CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid);
return(opret);
}
CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256>txids,int32_t height,uint256 cointxid,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount)
{
CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << destpub << amount);
return(opret);
}
uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector<CPubKey>&publishers,std::vector<uint256>&txids,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector<uint8_t> &proof,CPubKey &destpub,int64_t &amount)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 )
{
return(f);
}
return(0);
}
uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
depositaddr[0] = 0;
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> prefix; ss >> prefix2; ss >> taddr; ss >> tokenid; ss >> totalsupply; ss >> M; ss >> N; ss >> pubkeys; ss >> oracletxid) != 0 )
{
if ( prefix == 60 )
{
if ( N > 1 )
Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
}
else
{
fprintf(stderr,"need to generate non-KMD addresses prefix.%d\n",prefix);
}
return(f);
} else fprintf(stderr,"error decoding bind opret\n");
return(0);
}
int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{
char destaddr[64];
@@ -74,11 +250,12 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
else return(true);
}
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
fprintf(stderr,"return true without gateways validation\n");
return(true);
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
@@ -115,101 +292,607 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<uint8_t> vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
fprintf(stderr,"check %s for gateway inputs\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
for (j=0; j<mtx.vin.size(); j++)
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
break;
if ( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
//fprintf(stderr,"%s vout.%d %.8f %.8f\n",destaddr,vout,(double)vintx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret);
if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> assetid) != 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
assetid = revuint256(assetid);
//char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN);
if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
//fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN);
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
//nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
}
}
return(totalinputs);
}
std::string GatewaysGet(uint64_t txfee,int64_t nValue)
int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool!
{
CMutableTransaction mtx,tmpmtx; CPubKey mypk,Gatewayspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
Gatewayspk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddGatewaysInputs(cp,mtx,Gatewayspk,nValue+txfee,60)) > 0 )
char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys; CTransaction tx;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
_GetCCaddress(markeraddr,EVAL_GATEWAYS,gatewayspk);
fprintf(stderr,"bind markeraddr.(%s) need to scan mempool also\n",markeraddr);
SetCCtxids(addressIndex,markeraddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,Gatewayspk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_GATEWAYS << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' )
{
len >>= 1;
decode_hex(buf,len,(char *)rawhex.c_str());
hash = bits256_doublesha256(0,buf,len);
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
if ( tokenid == reftokenid )
{
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
return(rawhex);
fprintf(stderr,"trying to bind an existing tokenid\n");
return(1);
}
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
}
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find Gateways inputs\n");
return("");
}
std::string GatewaysFund(uint64_t txfee,int64_t funds)
{
CMutableTransaction mtx; CPubKey mypk,Gatewayspk; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
Gatewayspk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,funds,Gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
return("");
return(0);
}
UniValue GatewaysInfo()
static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr)
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int64_t funding;
int32_t i,n; char destaddr[64];
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
{
const CTransaction &tx = e.GetTx();
if ( (n= tx.vout.size()) > 0 )
{
const uint256 &txid = tx.GetHash();
for (i=0; i<n; i++)
{
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
if ( strcmp(destaddr,coinaddr) == 0 )
{
fprintf(stderr,"found (%s) vout in mempool\n",coinaddr);
return(1);
}
}
}
}
return(0);
}
int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool!
{
char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
CCtxidaddr(txidaddr,cointxid);
SetCCtxids(addressIndex,txidaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
return(-1);
}
return(myIs_coinaddr_inmempoolvout(txidaddr));
}
UniValue GatewaysInfo(uint256 bindtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector<CPubKey> pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Gateways"));
cp = CCinit(&C,EVAL_GATEWAYS);
Gatewayspk = GetUnspendable(cp,0);
funding = AddGatewaysInputs(cp,mtx,Gatewayspk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
_GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk);
if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
{
depositaddr[0] = 0;
if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 )
{
if ( N > 1 )
{
result.push_back(Pair("M",M));
result.push_back(Pair("N",N));
for (i=0; i<N; i++)
a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
result.push_back(Pair("pubkeys",a));
} else result.push_back(Pair("pubkey",pubkey33_str(str,(uint8_t *)&pubkeys[0])));
result.push_back(Pair("coin",coin));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
result.push_back(Pair("taddr",taddr));
result.push_back(Pair("prefix",prefix));
result.push_back(Pair("prefix2",prefix2));
result.push_back(Pair("deposit",depositaddr));
result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
sprintf(numstr,"%.8f",(double)totalsupply/COIN);
result.push_back(Pair("totalsupply",numstr));
remaining = CCaddress_balance(gatewaysassets);
sprintf(numstr,"%.8f",(double)remaining/COIN);
result.push_back(Pair("remaining",numstr));
sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
result.push_back(Pair("issued",numstr));
}
}
return(result);
}
UniValue GatewaysList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys;
cp = CCinit(&C,EVAL_GATEWAYS);
SetCCtxids(addressIndex,cp->unspendableCCaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 )
{
result.push_back(uint256_str(str,txid));
}
}
}
return(result);
}
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys)
{
CMutableTransaction mtx; CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( strcmp((char *)"KMD",coin.c_str()) == 0 )
{
taddr = 0;
prefix = 60;
prefix2 = 85;
}
else
{
fprintf(stderr,"set taddr, prefix, prefix2 for %s\n",coin.c_str());
taddr = 0;
prefix = 60;
prefix2 = 85;
}
if ( N == 0 || N > 15 || M > N )
{
fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
return("");
}
if ( pubkeys.size() != N )
{
fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
return("");
}
for (i=0; i<N; i++)
{
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
if ( CCaddress_balance(coinaddr) == 0 )
{
fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
return("");
}
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( _GetCCaddress(destaddr,EVAL_GATEWAYS,gatewayspk) == 0 )
{
fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
return("");
}
if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply )
{
fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s totalsupply %.8f != fullsupply %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN);
return("");
}
if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
{
fprintf(stderr,"Gateway bind.%s (%s) destaddr.%s globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),destaddr,cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
return("");
}
if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
{
fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str());
return("");
}
if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
{
fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
return("");
}
if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool!
{
fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid));
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2)));
}
fprintf(stderr,"cant find enough inputs\n");
return("");
}
uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
{
CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; int64_t val,merkleht; CPubKey pk; std::vector<uint8_t>data;
txid = zeroid;
char str[65];
//fprintf(stderr,"start reverse scan %s\n",uint256_str(str,batontxid));
while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
//fprintf(stderr,"check %s\n",uint256_str(str,batontxid));
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid )
{
//fprintf(stderr,"decoded %s\n",uint256_str(str,batontxid));
if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
{
len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size());
len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size());
char str2[65]; fprintf(stderr,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash));
if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid )
{
txid = batontxid;
//fprintf(stderr,"set txid\n");
return(mhash);
}
else
{
//fprintf(stderr,"missing hash\n");
return(zeroid);
}
} //else fprintf(stderr,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height);
batontxid = bhash;
//fprintf(stderr,"new hash %s\n",uint256_str(str,batontxid));
} else break;
}
fprintf(stderr,"end of loop\n");
return(zeroid);
}
/* Get the block merkle root for a proof
* IN: proofData
* OUT: merkle root
* OUT: transaction IDS
*/
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids)
{
CMerkleBlock merkleBlock;
if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
return uint256();
return merkleBlock.txn.ExtractMatches(txids);
}
int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vector<uint8_t>proof,uint256 merkleroot,CPubKey destpub)
{
std::vector<uint256> txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0;
if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
return(0);
}
if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
{
fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
return(0);
}
proofroot = BitcoinGetProofMerkleRoot(proof,txids);
if ( proofroot != merkleroot )
{
fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot));
return(0);
}
if ( DecodeHexTx(tx,deposithex) != 0 )
{
Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey);
Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
if ( strcmp(claimaddr,destpubaddr) == 0 )
{
for (i=0; i<numvouts; i++)
{
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
if ( strcmp(refdepositaddr,destaddr) == 0 )
{
txid = tx.GetHash();
nValue = tx.vout[i].nValue;
break;
}
}
} else fprintf(stderr,"claimaddr.(%s) != destpubaddr.(%s)\n",claimaddr,destpubaddr);
}
if ( txid == cointxid )
{
fprintf(stderr,"verified proof for cointxid in merkleroot\n");
return(nValue);
} else fprintf(stderr,"(%s) != (%s) or txid %s mismatch.%d or script mismatch\n",refdepositaddr,destaddr,uint256_str(str,txid),txid != cointxid);
return(0);
}
int64_t GatewaysDepositval(CTransaction tx,CPubKey mypk)
{
int32_t numvouts,height; int64_t amount; std::string coin,deposithex; std::vector<CPubKey> publishers; std::vector<uint256>txids; uint256 bindtxid,cointxid; std::vector<uint8_t> proof; CPubKey claimpubkey;
if ( (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk )
{
// coin, bindtxid, publishers
fprintf(stderr,"need to validate deposittxid more\n");
return(amount);
}
}
return(0);
}
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector<CPubKey> pubkeys,publishers; std::vector<uint256>txids; char str[67],depositaddr[64],txidaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
//fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size());
if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
n = (int32_t)pubkeys.size();
merkleroot = zeroid;
for (i=m=0; i<n; i++)
{
fprintf(stderr,"pubkeys[%d] %s\n",i,pubkey33_str(str,(uint8_t *)&pubkeys[i]));
if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i]))) != zeroid )
{
if ( merkleroot == zeroid )
merkleroot = mhash, m = 1;
else if ( mhash == merkleroot )
m++;
publishers.push_back(pubkeys[i]);
txids.push_back(txid);
}
}
fprintf(stderr,"cointxid.%s m.%d of n.%d\n",uint256_str(str,cointxid),m,n);
if ( merkleroot == zeroid || m < n/2 )
{
//uint256 tmp;
//decode_hex((uint8_t *)&tmp,32,(char *)"90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f");
//merkleroot = revuint256(tmp);
fprintf(stderr,"couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d\n",height,coin.c_str(),uint256_str(str,oracletxid),m,n);
return("");
}
if ( GatewaysCointxidExists(cp,cointxid) != 0 )
{
fprintf(stderr,"cointxid.%s already exists\n",uint256_str(str,cointxid));
return("");
}
if ( GatewaysVerify(depositaddr,oracletxid,claimvout,coin,cointxid,deposithex,proof,merkleroot,destpub) != amount )
{
fprintf(stderr,"deposittxid didnt validate\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount)));
}
fprintf(stderr,"cant find enough inputs\n");
return("");
}
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64],coinaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find deposittxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount )
{
fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
return("");
}
//fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2);
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65],coinaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
{
if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk));
mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid)
{
CMutableTransaction mtx; CScript opret; CPubKey mypk; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 5000;
mypk = pubkey2pk(Mypubkey());
mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript()));
mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'M' << cointxid << refcoin);
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
{
UniValue result(UniValue::VOBJ),pending(UniValue::VARR),obj(UniValue::VOBJ); CTransaction tx; std::string coin; CPubKey mypk,gatewayspk; std::vector<CPubKey> msigpubkeys; uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
cp = CCinit(&C,EVAL_GATEWAYS);
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return(result);
}
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return(result);
}
n = msigpubkeys.size();
queueflag = 0;
for (i=0; i<n; i++)
if ( msigpubkeys[i] == mypk )
{
queueflag = 1;
break;
}
Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG);
SetCCunspents(unspentOutputs,withmarker);
numqueued = 0;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 )
{
Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
Getscriptaddress(withaddr,tx.vout[1].scriptPubKey);
if ( strcmp(destaddr,coinaddr) == 0 )
{
obj.push_back(Pair("txid",uint256_str(str,txid)));
CCtxidaddr(txidaddr,txid);
obj.push_back(Pair("txidaddr",txidaddr));
obj.push_back(Pair("withdrawaddr",withaddr));
sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN);
obj.push_back(Pair("amount",numstr));
if ( queueflag != 0 )
{
obj.push_back(Pair("depositaddr",depositaddr));
Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG);
obj.push_back(Pair("signeraddr",signeraddr));
}
pending.push_back(obj);
}
}
}
result.push_back(Pair("coin",refcoin));
result.push_back(Pair("pending",pending));
result.push_back(Pair("queueflag",queueflag));
return(result);
}
std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr)
{
UniValue result(UniValue::VOBJ); std::string coin,hex; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector<CPubKey> pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk,mypk; struct CCcontract_info *cp,C; int32_t i,n,complete,partialtx; int64_t totalsupply;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
complete = partialtx = 0;
mypk = pubkey2pk(Mypubkey());
Gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk);
if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
{
depositaddr[0] = 0;
if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 1 && coin == refcoin )
{
// need a decentralized way to add signatures to msig tx
n = pubkeys.size();
for (i=0; i<n; i++)
if ( mypk == pubkeys[i] )
break;
if ( i != n )
{
hex = "";
} else fprintf(stderr,"not one of the multisig signers\n");
}
}
return(hex);
}

View File

@@ -157,7 +157,8 @@ uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint25
{
if ( e == EVAL_ORACLES && f == 'D' )
return(f);
}
//else fprintf(stderr,"DecodeOraclesData evalcode.%d f.%c\n",e,f);
} //else fprintf(stderr,"DecodeOraclesData not enough opereturn data\n");
return(0);
}
@@ -169,6 +170,7 @@ CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
Myprivkey(priv);
cp->evalcode2 = EVAL_ORACLES;
for (i=0; i<32; i++)
cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
@@ -222,22 +224,33 @@ int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publ
int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher)
{
CTransaction oracletx; char markeraddr[64]; CPubKey markerpubkey; uint8_t buf33[33]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0;
CTransaction oracletx; char markeraddr[64]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0;
if ( myGetTransaction(oracletxid,oracletx,hashBlock) != 0 && (numvouts= oracletx.vout.size()) > 0 )
{
if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
{
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
markerpubkey = buf2pk(buf33);
scriptPubKey = CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG;
Getscriptaddress(markeraddr,scriptPubKey);
CCtxidaddr(markeraddr,oracletxid);
datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher);
}
}
return(datafee);
}
static uint256 myIs_baton_spentinmempool(uint256 batontxid,int32_t batonvout)
{
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
{
const CTransaction &tx = e.GetTx();
if ( tx.vout.size() > 0 && tx.vin.size() > 1 && batontxid == tx.vin[1].prevout.hash && batonvout == tx.vin[1].prevout.n )
{
const uint256 &txid = tx.GetHash();
//char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid));
return(txid);
}
}
return(batontxid);
}
uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector <uint8_t> &dataarg)
{
uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector<uint8_t> vopret,data;
@@ -276,6 +289,35 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
}
}
}
while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
batontxid = myIs_baton_spentinmempool(batontxid,1);
return(batontxid);
}
uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
{
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction regtx; uint256 hash,txid,batontxid,oracletxid; CPubKey pk; int32_t numvouts,height,maxheight=0; int64_t datafee; char markeraddr[64],batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C;
batontxid = zeroid;
cp = CCinit(&C,EVAL_ORACLES);
CCtxidaddr(markeraddr,reforacletxid);
SetCCunspents(unspentOutputs,markeraddr);
//char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
//fprintf(stderr,"check %s\n",uint256_str(str,txid));
height = (int32_t)it->second.blockHeight;
if ( myGetTransaction(txid,regtx,hash) != 0 )
{
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid && pk == refpk )
{
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
break;
}
}
}
return(batontxid);
}
@@ -389,7 +431,6 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
int32_t i,j; int64_t price = 0;
if ( n == 1 )
return(prices[0]);
// deterministic sort, like heapsort
for (i=0; i<n; i++)
{
j = (height + i) % n;
@@ -401,63 +442,92 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height);
}
int64_t OracleCorrelatedPrice(int32_t height,char *format,std::vector <uint8_t> datas[ORACLES_MAXPROVIDERS],int32_t n)
int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
{
int64_t prices[ORACLES_MAXPROVIDERS]; int32_t i,m=0; uint256 hash; int64_t val,price=0;
if ( format[0] == 'L' )
std::vector <int64_t> sorted; int32_t i,n; int64_t *prices,price;
if ( (n= origprices.size()) == 1 )
return(origprices[0]);
std::sort(origprices.begin(), origprices.end());
prices = (int64_t *)calloc(n,sizeof(*prices));
i = 0;
for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
prices[i++] = *it;
price = correlate_price(height,prices,i);
free(prices);
return(price);
}
int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey pk,int32_t height,std::vector <uint8_t> data,int32_t maxheight)
{
struct oracleprice_info item; int32_t flag = 0;
for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
{
for (i=0; i<n; i++)
if ( pk == it->pk )
{
oracle_format(&hash,&val,0,'L',(uint8_t *)datas[i].data(),0,(int32_t)datas[i].size());
if ( val != 0 )
prices[m++] = val;
flag = 1;
if ( height > it->height )
{
it->height = height;
it->data = data;
return(height);
}
}
}
if ( m != 0 )
price = correlate_price(height,prices,m);
return(0);
if ( flag == 0 )
{
item.pk = pk;
item.data = data;
item.height = height;
publishers.push_back(item);
return(height);
} else return(0);
}
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
{
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction regtx,tx; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk,providers[ORACLES_MAXPROVIDERS]; int32_t i,j,n=0; int64_t datafee; char batonaddr[64]; std::vector <uint8_t> data,datas[ORACLES_MAXPROVIDERS]; struct CCcontract_info *cp,C;
CTransaction regtx; uint256 hash,txid,oracletxid,batontxid; CPubKey pk; int32_t i,ht,maxheight=0; int64_t datafee,price; char batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C; std::vector <struct oracleprice_info> publishers; std::vector <int64_t> prices;
if ( format[0] != 'L' )
return(0);
cp = CCinit(&C,EVAL_ORACLES);
SetCCunspents(unspentOutputs,markeraddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( myGetTransaction(txid,regtx,hashBlock) != 0 )
ht = (int32_t)it->second.blockHeight;
if ( myGetTransaction(txid,regtx,hash) != 0 )
{
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
{
for (j=0; j<n; j++)
if ( pk == providers[j] )
break;
if ( j == n )
{
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
if ( batontxid != zeroid )
{
datas[n] = data;
providers[n++] = pk;
if ( n == ORACLES_MAXPROVIDERS )
break;
}
}
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight )
maxheight = ht;
}
}
}
return(OracleCorrelatedPrice(height,format,datas,n));
if ( maxheight > 10 )
{
for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
{
if ( it->height >= maxheight-10 )
{
oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
if ( price != 0 )
prices.push_back(price);
}
}
return(OracleCorrelatedPrice(height,prices));
}
return(0);
}
int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{
char destaddr[64];
//char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 )// && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
//if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
@@ -485,8 +555,8 @@ bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransactio
else
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant Oracles from mempool");
//if ( hashBlock == zerohash )
// return eval->Invalid("cant Oracles from mempool");
if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
{
if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey )
@@ -600,6 +670,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
//char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout);
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
// get valid CC payments
@@ -612,8 +683,8 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
} //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN);
} else fprintf(stderr,"couldnt find transaction\n");
}
return(totalinputs);
}
@@ -662,7 +733,7 @@ std::string OracleCreate(int64_t txfee,std::string name,std::string description,
std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
{
CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64],batonaddr[64];
CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64];
cp = CCinit(&C,EVAL_ORACLES);
if ( txfee == 0 )
txfee = 10000;
@@ -672,11 +743,8 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
return("");
}
mypk = pubkey2pk(Mypubkey());
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
batonpk = OracleBatonPk(batonaddr,cp);
markerpubkey = CCtxidaddr(markeraddr,oracletxid);
if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
{
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
@@ -688,15 +756,12 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
{
CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64];
CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64];
cp = CCinit(&C,EVAL_ORACLES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
markerpubkey = CCtxidaddr(markeraddr,oracletxid);
if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
@@ -739,8 +804,8 @@ std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> da
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data)));
}
}
} else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n");
} else fprintf(stderr,"couldnt add normal inputs\n");
return("");
}
@@ -790,12 +855,9 @@ UniValue OracleInfo(uint256 origtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey markerpubkey,pk; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
cp = CCinit(&C,EVAL_ORACLES);
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&origtxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
CCtxidaddr(markeraddr,origtxid);
if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
{
if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )

View File

@@ -28,63 +28,60 @@
Funds work like with dice, ie. there is a Prices plan that traders bet against.
PricesOpen -> oracletxid start with 'L' price, leverage, amount
funds are locked into global CC address
PricesFunding oracletxid, margin, priceaveraging, maxleverage, funding, longtoken, shorttoken, N [pubkeys]
PricesBet -> oracletxid start with 'L', leverage, funding, direction
funds are locked into global CC address
it can be closed at anytime by the trader for cash settlement
the house account can close it if rekt
Implementation Notes:
In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers.
delta neutral balancing of riskexposure: fabs(long exposure - short exposure)
bet +B at leverage L
absval(sum(+BLi) - sum(-Bli))
validate: update riskexposure and it needs to be <= funds
PricesProfits: limit withdraw to funds in excess of riskexposure
PricesFinish: payout (if winning) and update riskexposure
need long/short exposure assets
funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address
pricebet -> user funds and exposure token to 1of2 address.
pricewin -> winnings from dealer funds, exposure token back to global address
priceloss -> exposuretoken back to global address
exposure address, funds address
*/
// start of consensus code
int64_t IsPricesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vector<CPubKey>pubkeys,int32_t dir,int64_t amount,int32_t leverage)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
int64_t price;
// howto ensure price when block it confirms it not known
// get price from oracle + current chaintip
// normalize leveraged amount
if ( dir > 0 )
rektprice = price * leverage / (leverage-1);
else rektprice = price * (leverage-1) / leverage;
return(price);
}
bool PricesExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector<CPubKey> pubkeys,uint256 bettoken)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=0; i<numvins; i++)
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
{
//fprintf(stderr,"vini.%d check mempool\n",i);
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("cant find vinTx");
else
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant Prices from mempool");
if ( (assetoshis= IsPricesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
}
}
}
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsPricesvout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+txfee )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
return eval->Invalid("mismatched inputs != outputs + txfee");
}
else return(true);
CScript opret;
fprintf(stderr,"implement EncodePricesFundingOpRet\n");
return(opret);
}
uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector<CPubKey> &pubkeys,uint256 &bettoken)
{
fprintf(stderr,"implement DecodePricesFundingOpRet\n");
return(0);
}
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
@@ -107,12 +104,12 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
}
}
//fprintf(stderr,"check amounts\n");
if ( PricesExactAmounts(cp,eval,tx,1,10000) == false )
//if ( PricesExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"Pricesget invalid amount\n");
return false;
}
else
//else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
@@ -128,20 +125,20 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,destaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
// need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() )
{
if ( (nValue= IsPricesvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
// need to verify assetid
if ( (nValue= vintx.vout[vout].nValue) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -156,69 +153,18 @@ int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
return(totalinputs);
}
/*
UniValue PriceInfo(uint256 origtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey markerpubkey,pk; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
cp = CCinit(&C,EVAL_ORACLES);
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&origtxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
{
if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("txid",uint256_str(str,origtxid)));
result.push_back(Pair("name",name));
result.push_back(Pair("description",description));
result.push_back(Pair("format",format));
result.push_back(Pair("marker",markeraddr));
SetCCunspents(unspentOutputs,markeraddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
{
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
{
obj.push_back(Pair("provider",pubkey33_str(str,(uint8_t *)pk.begin())));
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
obj.push_back(Pair("baton",batonaddr));
obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
funding = LifetimeOraclesFunds(cp,oracletxid,pk);
sprintf(numstr,"%.8f",(double)funding/COIN);
obj.push_back(Pair("lifetime",numstr));
funding = AddOracleInputs(cp,mtx,pk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
obj.push_back(Pair("funds",numstr));
sprintf(numstr,"%.8f",(double)datafee/COIN);
obj.push_back(Pair("datafee",numstr));
a.push_back(obj);
}
}
}
result.push_back(Pair("registered",a));
}
}
return(result);
}
UniValue PricesList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65];
cp = CCinit(&C,EVAL_ORACLES);
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vector<CPubKey>pubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx;
cp = CCinit(&C,EVAL_PRICES);
pricespk = GetUnspendable(cp,0);
SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(uint256_str(str,txid));
}
@@ -226,4 +172,273 @@ UniValue PricesList()
}
return(result);
}
*/
// longtoken satoshis limits long exposure
// shorttoken satoshis limits short exposure
// both must be in the 1of2 CC address with its total supply
// bettoken
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys)
{
CMutableTransaction mtx; CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C,*assetscp,C2;
if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 )
{
CCerror = "invalid parameter error";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
if ( (N= (int32_t)pubkeys.size()) || N > 15 )
{
fprintf(stderr,"too many pubkeys N.%d\n",N);
return("");
}
for (i=0; i<N; i++)
{
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
if ( CCaddress_balance(coinaddr) == 0 )
{
fprintf(stderr,"N.%d but pubkeys[%d] has no balance\n",N,i);
return("");
}
}
if ( GetCCaddress1of2(cp,houseaddr,pricespk,mypk) == 0 )
{
fprintf(stderr,"PricesCreateFunding cant create globaladdr\n");
return("");
}
if ( CCtoken_balance(houseaddr,longtoken) != CCfullsupply(longtoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(longtoken)/COIN);
return("");
}
if ( CCtoken_balance(houseaddr,shorttoken) != CCfullsupply(shorttoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(shorttoken)/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
return("");
}
fprintf(stderr,"error check bettoken\n");
if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
{
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken)));
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
return("");
}
UniValue PricesInfo(uint256 fundingtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vector<CPubKey>pubkeys; struct CCcontract_info *cp,C,*assetscp,C2;
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_ASSETS);
pricespk = GetUnspendable(cp,0);
if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
ERR_RESULT("cant find fundingtxid");
return(result);
}
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid)));
result.push_back(Pair("bettoken",uint256_str(str,bettoken)));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
sprintf(numstr,"%.3f",(double)margin/1000);
result.push_back(Pair("profitmargin",numstr));
result.push_back(Pair("maxleverage",maxleverage));
result.push_back(Pair("mode",(int64_t)mode));
for (i=0; i<pubkeys.size(); i++)
a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
result.push_back(Pair("pubkeys",a));
GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk);
GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk); // assets addr
result.push_back(Pair("houseaddr",houseaddr));
result.push_back(Pair("betaddr",exposureaddr));
result.push_back(Pair("longtoken",uint256_str(str,longtoken)));
supply = CCfullsupply(longtoken);
result.push_back(Pair("longsupply",supply));
balance = CCtoken_balance(houseaddr,longtoken);
result.push_back(Pair("longavail",balance));
exposure = CCtoken_balance(exposureaddr,longtoken);
result.push_back(Pair("longexposure",exposure));
result.push_back(Pair("shorttoken",uint256_str(str,shorttoken)));
supply = CCfullsupply(shorttoken);
result.push_back(Pair("shortsupply",supply));
balance = CCtoken_balance(houseaddr,shorttoken);
result.push_back(Pair("shortavail",balance));
exposure = CCtoken_balance(exposureaddr,shorttoken);
result.push_back(Pair("shortexposure",exposure));
sprintf(numstr,"%.8f",(double)CCtoken_balance(houseaddr,bettoken)/COIN);
result.push_back(Pair("funds",numstr));
}
return(result);
}
std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount)
{
CMutableTransaction mtx; struct CCcontract_info *cp,C,*assetscp,C2; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,CCchange = 0; uint64_t funding,mode; int32_t margin,maxleverage; char houseaddr[64],myaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 10000 )
{
CCerror = "amount must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(assetscp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk);
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
{
if ( (inputs= AddTokensInputs(assetscp,mtx,myaddr,bettoken,amount,60)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG));
if ( inputs > amount+txfee )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(assetscp->evalcode,CCchange,mypk));
// add addr2
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0,Mypubkey())));
}
else
{
CCerror = "cant find enough bet inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
return("");
}
std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage)
{
CMutableTransaction mtx; struct CCcontract_info *cp,C,*assetscp,C2; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 0 )
{
amount = -amount;
dir = -1;
} else dir = 1;
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(assetscp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
if ( leverage > maxleverage || leverage < 1 )
{
fprintf(stderr,"illegal leverage\n");
return("");
}
GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk);
GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk);
if ( dir < 0 )
tokenid = shorttoken;
else tokenid = longtoken;
exposure = leverage * amount;
longexposure = CCtoken_balance(exposureaddr,longtoken);
shortexposure = CCtoken_balance(exposureaddr,shorttoken);
netexposure = (longexposure - shortexposure + exposure*dir);
if ( netexposure < 0 )
netexposure = -netexposure;
balance = CCtoken_balance(myaddr,bettoken) / COIN;
if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction
{
fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure);
return("");
}
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
{
if ( (inputs= AddTokensInputs(assetscp,mtx,houseaddr,tokenid,exposure,30)) >= exposure )
{
if ( (inputs2= AddTokensInputs(assetscp,mtx,myaddr,bettoken,amount,30)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,exposure,pricespk,pricespk));
if ( inputs > exposure+txfee )
CCchange = (inputs - exposure);
if ( inputs2 > amount+txfee )
CCchange2 = (inputs2 - amount);
mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,CCchange,pricespk,planpk));
mtx.vout.push_back(MakeCC1vout(assetscp->evalcode,CCchange2,mypk));
// add addr2 and addr3
//return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage)));
CScript opret;
return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,opret));
}
else
{
fprintf(stderr,"cant find enough bettoken inputs\n");
return("");
}
}
else
{
fprintf(stderr,"cant find enough exposure inputs\n");
return("");
}
}
else
{
CCerror = "cant find enough inputsB";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
return("");
}
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
{
UniValue result(UniValue::VOBJ);
// get height of bettxid
// get price and rekt
// get current height and price
// what about if rekt in the past?
return(result);
}
std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
{
return("");
}

View File

@@ -294,7 +294,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
return(true);
}
uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed)
static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed)
{
uint8_t funcid; uint64_t sbits,nValue; uint256 fundingtxid; char str[65];
memset(&txid,0,sizeof(txid));

View File

@@ -40,3 +40,6 @@ curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dp
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"VRSC\",\"freq\":10,\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SEC\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CCL\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"HUSH\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"PIRATE\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MGNX\",\"pubkey\":\"$pubkey\"}"

2
src/fiat/mgnx Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6

2
src/fiat/pirate Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6

View File

@@ -29,6 +29,7 @@ uint64_t komodo_paxtotal();
int32_t komodo_longestchain();
uint64_t komodo_maxallowed(int32_t baseid);
int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max);
bool pubkey2addr(char *destaddr,uint8_t *pubkey33);
pthread_mutex_t komodo_mutex;

View File

@@ -202,6 +202,7 @@ const char *Notaries_elected1[][2] =
{"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" },
{"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" },
};
#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp)
{

View File

@@ -1628,6 +1628,11 @@ void komodo_args(char *argv0)
{
int32_t komodo_baseid(char *origbase);
extern int COINBASE_MATURITY;
if ( strcmp(ASSETCHAINS_SYMBOL,"KMD") == 0 )
{
fprintf(stderr,"cant have assetchain named KMD\n");
exit(0);
}
if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 )
ASSETCHAINS_RPCPORT = port;
else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1);
@@ -1699,6 +1704,11 @@ void komodo_args(char *argv0)
{
BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT);
//fprintf(stderr,"(%s) port.%u chain params initialized\n",ASSETCHAINS_SYMBOL,BITCOIND_RPCPORT);
if ( strcmp("PIRATE",ASSETCHAINS_SYMBOL) == 0 && ASSETCHAINS_HALVING == 77777 )
{
ASSETCHAINS_HALVING *= 5;
fprintf(stderr,"PIRATE halving changed to %d %.1f days\n",(int32_t)ASSETCHAINS_HALVING,(double)ASSETCHAINS_HALVING/1440);
}
} else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort());
}

View File

@@ -60,6 +60,8 @@ extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN,KOMODO_INSYNC,KOMODO_CON
int32_t KOMODO_NEWBLOCKS;
int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block);
void komodo_broadcast(CBlock *pblock,int32_t limit);
void komodo_broadcast(CBlock *pblock,int32_t limit);
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
BlockMap mapBlockIndex;
CChain chainActive;
@@ -1041,6 +1043,28 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state,
}
}
int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only
{
static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64];
int32_t i;
if ( didinit == 0 )
{
uint8_t pubkey33[33];
for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++)
{
if ( i < sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) )
decode_hex(pubkey33,33,(char *)Notaries_elected1[i][1]);
else decode_hex(pubkey33,33,(char *)CRYPTO777_PUBSECPSTR);
pubkey2addr((char *)notaryaddrs[i],(uint8_t *)pubkey33);
}
didinit = 1;
}
for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++)
if ( strcmp(coinaddr,notaryaddrs[i]) == 0 )
return(1);
return(0);
}
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
@@ -1117,9 +1141,14 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
}
if ( ASSETCHAINS_PRIVATE != 0 )
{
fprintf(stderr,"private chain nValue %.8f iscoinbase.%d\n",(double)txout.nValue/COIN,iscoinbase);
//fprintf(stderr,"private chain nValue %.8f iscoinbase.%d\n",(double)txout.nValue/COIN,iscoinbase);
if ( (txout.nValue > 0 && iscoinbase == 0) || tx.GetJoinSplitValueOut() > 0 )
return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain");
{
char destaddr[65];
Getscriptaddress(destaddr,txout.scriptPubKey);
if ( komodo_isnotaryvout(destaddr) == 0 )
return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain");
}
}
if ( txout.scriptPubKey.size() > IGUANA_MAXSCRIPTSIZE )
return state.DoS(100, error("CheckTransaction(): txout.scriptPubKey.size() too big"),REJECT_INVALID, "bad-txns-vout-negative");
@@ -3375,6 +3404,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete,1))
return AbortNode(state, "Failed to read block");
//if ( ASSETCHAINS_SYMBOL[0] != 0 || pindexDelete->nHeight > 1400000 )
{
int32_t prevMoMheight; uint256 notarizedhash,txid;
komodo_notarized_height(&prevMoMheight,&notarizedhash,&txid);
@@ -3626,23 +3656,34 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
// our genesis block. In practice this (probably) won't happen because of checks elsewhere.
auto reorgLength = pindexOldTip ? pindexOldTip->nHeight - (pindexFork ? pindexFork->nHeight : -1) : 0;
static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance");
if (reorgLength > MAX_REORG_LENGTH) {
auto msg = strprintf(_(
"A block chain reorganization has been detected that would roll back %d blocks! "
"This is larger than the maximum of %d blocks, and so the node is shutting down for your safety."
), reorgLength, MAX_REORG_LENGTH) + "\n\n" +
_("Reorganization details") + ":\n" +
"- " + strprintf(_("Current tip: %s, height %d, work %s"),
pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" +
"- " + strprintf(_("New tip: %s, height %d, work %s"),
pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" +
"- " + strprintf(_("Fork point: %s %s, height %d"),
ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" +
_("Please help, human!");
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return false;
if (reorgLength > MAX_REORG_LENGTH)
{
int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid;
notarizedht = komodo_notarized_height(&prevMoMheight,&notarizedhash,&txid);
if ( pindexFork->nHeight < notarizedht )
{
fprintf(stderr,"pindexFork->nHeight.%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->nHeight,notarizedht);
pindexFork = pindexOldTip;
}
else
{
auto msg = strprintf(_(
"A block chain reorganization has been detected that would roll back %d blocks! "
"This is larger than the maximum of %d blocks, and so the node is shutting down for your safety."
), reorgLength, MAX_REORG_LENGTH) + "\n\n" +
_("Reorganization details") + ":\n" +
"- " + strprintf(_("Current tip: %s, height %d, work %s"),
pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" +
"- " + strprintf(_("New tip: %s, height %d, work %s"),
pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" +
"- " + strprintf(_("Fork point: %s %s, height %d"),
ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" +
_("Please help, human!");
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return false;
}
}
// Disconnect active blocks which are no longer in the best chain.

View File

@@ -107,6 +107,11 @@ static UniValue ValuePoolDesc(
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
UniValue result(UniValue::VOBJ);
if ( blockindex == 0 )
{
result.push_back(Pair("error", "null blockhash"));
return(result);
}
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
// Only report confirmations if the block is on the main chain
@@ -1372,6 +1377,8 @@ struct CompareBlocksByHeight
}
};
#include <pthread.h>
UniValue getchaintips(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -1410,17 +1417,33 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
/* Build up a list of chain tips. We start with the list of all
known blocks, and successively remove blocks that appear as pprev
of another block. */
/*static pthread_mutex_t mutex; static int32_t didinit;
if ( didinit == 0 )
{
pthread_mutex_init(&mutex,NULL);
didinit = 1;
}
pthread_mutex_lock(&mutex);*/
std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
int32_t n = 0;
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
n++;
setTips.insert(item.second);
}
fprintf(stderr,"iterations getchaintips %d\n",n);
n = 0;
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
const CBlockIndex* pprev=0;
n++;
if ( item.second != 0 )
pprev = item.second->pprev;
if (pprev)
setTips.erase(pprev);
}
fprintf(stderr,"iterations getchaintips %d\n",n);
//pthread_mutex_unlock(&mutex);
// Always report the currently active tip.
setTips.insert(chainActive.LastTip());

View File

@@ -141,7 +141,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "z_importviewingkey", 2 },
{ "z_getpaymentdisclosure", 1},
{ "z_getpaymentdisclosure", 2},
// crosschain
{ "assetchainproof", 1},
{ "crosschainproof", 1},
@@ -195,7 +194,6 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
const std::string& strVal = strParams[idx];
if (!rpcCvtTable.convert(strMethod, idx)) {
// insert string value directly
params.push_back(strVal);

View File

@@ -299,9 +299,9 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
{ "blockchain", "verifychain", &verifychain, true },
{ "blockchain", "getspentinfo", &getspentinfo, false },
{ "blockchain", "paxprice", &paxprice, true },
{ "blockchain", "paxpending", &paxpending, true },
{ "blockchain", "paxprices", &paxprices, true },
//{ "blockchain", "paxprice", &paxprice, true },
//{ "blockchain", "paxpending", &paxpending, true },
//{ "blockchain", "paxprices", &paxprices, true },
{ "blockchain", "notaries", &notaries, true },
//{ "blockchain", "height_MoM", &height_MoM, true },
//{ "blockchain", "txMoMproof", &txMoMproof, true },
@@ -356,9 +356,9 @@ static const CRPCCommand vRPCCommands[] =
/* fsm */
{ "FSM", "FSMaddress", &FSMaddress, true },
{ "FSMcreate", "FSMcreate", &FSMcreate, true },
{ "FSMlist", "FSMlist", &FSMlist, true },
{ "FSMinfo", "FSMinfo", &FSMinfo, true },
{ "FSM", "FSMcreate", &FSMcreate, true },
{ "FSM", "FSMlist", &FSMlist, true },
{ "FSM", "FSMinfo", &FSMinfo, true },
/* rewards */
{ "rewards", "rewardslist", &rewardslist, true },
@@ -398,7 +398,14 @@ static const CRPCCommand vRPCCommands[] =
{ "oracles", "oraclessamples", &oraclessamples, true },
/* Prices */
{ "prices", "pricesaddress", &pricesaddress, true },
{ "prices", "pricesaddress", &pricesaddress, true },
{ "prices", "priceslist", &priceslist, true },
{ "prices", "pricesinfo", &pricesinfo, true },
{ "prices", "pricescreate", &pricescreate, true },
{ "prices", "pricesaddfunding", &pricesaddfunding, true },
{ "prices", "pricesbet", &pricesbet, true },
{ "prices", "pricesstatus", &pricesstatus, true },
{ "prices", "pricesfinish", &pricesfinish, true },
/* Pegs */
{ "pegs", "pegsaddress", &pegsaddress, true },
@@ -411,6 +418,15 @@ static const CRPCCommand vRPCCommands[] =
/* Gateways */
{ "gateways", "gatewaysaddress", &gatewaysaddress, true },
{ "gateways", "gatewayslist", &gatewayslist, true },
{ "gateways", "gatewaysinfo", &gatewaysinfo, true },
{ "gateways", "gatewaysbind", &gatewaysbind, true },
{ "gateways", "gatewaysdeposit", &gatewaysdeposit, true },
{ "gateways", "gatewaysclaim", &gatewaysclaim, true },
{ "gateways", "gatewayswithdraw", &gatewayswithdraw, true },
{ "gateways", "gatewayspending", &gatewayspending, true },
{ "gateways", "gatewaysmultisig", &gatewaysmultisig, true },
{ "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true },
/* dice */
{ "dice", "dicelist", &dicelist, true },
@@ -438,6 +454,7 @@ static const CRPCCommand vRPCCommands[] =
{ "tokens", "tokencancelask", &tokencancelask, true },
{ "tokens", "tokenfillask", &tokenfillask, true },
//{ "tokens", "tokenfillswap", &tokenfillswap, true },
{ "tokens", "tokenconvert", &tokenconvert, true },
/* Address index */
{ "addressindex", "getaddressmempool", &getaddressmempool, true },

View File

@@ -221,6 +221,7 @@ extern UniValue tokenfillbid(const UniValue& params, bool fHelp);
extern UniValue tokenask(const UniValue& params, bool fHelp);
extern UniValue tokencancelask(const UniValue& params, bool fHelp);
extern UniValue tokenfillask(const UniValue& params, bool fHelp);
extern UniValue tokenconvert(const UniValue& params, bool fHelp);
extern UniValue mofnaddress(const UniValue& params, bool fHelp);
extern UniValue channelsaddress(const UniValue& params, bool fHelp);
extern UniValue oraclesaddress(const UniValue& params, bool fHelp);
@@ -232,11 +233,28 @@ extern UniValue oraclessubscribe(const UniValue& params, bool fHelp);
extern UniValue oraclesdata(const UniValue& params, bool fHelp);
extern UniValue oraclessamples(const UniValue& params, bool fHelp);
extern UniValue pricesaddress(const UniValue& params, bool fHelp);
extern UniValue priceslist(const UniValue& params, bool fHelp);
extern UniValue pricesinfo(const UniValue& params, bool fHelp);
extern UniValue pricescreate(const UniValue& params, bool fHelp);
extern UniValue pricesaddfunding(const UniValue& params, bool fHelp);
extern UniValue pricesbet(const UniValue& params, bool fHelp);
extern UniValue pricesstatus(const UniValue& params, bool fHelp);
extern UniValue pricesfinish(const UniValue& params, bool fHelp);
extern UniValue pegsaddress(const UniValue& params, bool fHelp);
extern UniValue triggersaddress(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
extern UniValue gatewaysaddress(const UniValue& params, bool fHelp);
extern UniValue gatewayslist(const UniValue& params, bool fHelp);
extern UniValue gatewaysinfo(const UniValue& params, bool fHelp);
extern UniValue gatewaysbind(const UniValue& params, bool fHelp);
extern UniValue gatewaysdeposit(const UniValue& params, bool fHelp);
extern UniValue gatewaysclaim(const UniValue& params, bool fHelp);
extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp);
extern UniValue gatewayspending(const UniValue& params, bool fHelp);
extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp);
extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp);
extern UniValue channelsinfo(const UniValue& params, bool fHelp);
extern UniValue channelsbind(const UniValue& params, bool fHelp);
extern UniValue channelsopen(const UniValue& params, bool fHelp);
extern UniValue channelspayment(const UniValue& params, bool fHelp);
extern UniValue channelscollect(const UniValue& params, bool fHelp);

View File

@@ -398,7 +398,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
// Parse Zcash address
CScript scriptPubKey = GetScriptForDestination(address);
// Create and send the transaction
CReserveKey reservekey(pwalletMain);
CAmount nFeeRequired;
@@ -430,6 +430,8 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
int32_t komodo_isnotaryvout(char *coinaddr);
UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -460,8 +462,12 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
);
if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
{
if ( komodo_isnotaryvout((char *)params[0].get_str().c_str()) == 0 )
{
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
}
}
LOCK2(cs_main, pwalletMain->cs_wallet);
CBitcoinAddress address(params[0].get_str());
@@ -4857,6 +4863,8 @@ int32_t ensure_CCrequirements()
#include "../cc/CClotto.h"
#include "../cc/CCchannels.h"
#include "../cc/CCOracles.h"
#include "../cc/CCGateways.h"
#include "../cc/CCPrices.h"
UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
{
@@ -4875,6 +4883,12 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned ch
result.push_back(Pair(str,cp->unspendableCCaddr));
sprintf(str,"%smarker",name);
result.push_back(Pair(str,cp->normaladdr));
result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40"));
if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 )
{
sprintf(str,"%sCCassets",name);
result.push_back(Pair(str,destaddr));
}
if ( pubkey.size() == 33 )
{
if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
@@ -4889,7 +4903,7 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned ch
UniValue channelsaddress(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 1 )
throw runtime_error("channelsaddress destpubkey\n");
@@ -4902,6 +4916,15 @@ UniValue channelsaddress(const UniValue& params, bool fHelp)
result.push_back(Pair("otherpubkey", params[0].get_str()));
GetCCaddress1of2(cp,destaddr,pk,pk2);
result.push_back(Pair("channeladdress",destaddr));
if ( 0 )
{
int32_t i;
for (i=0; i<100; i++)
{
GetCCaddress1of2(cp,destaddr,pk,pk2);
fprintf(stderr,"i.%d %s\n",i,destaddr);
}
}
return(result);
}
@@ -4920,15 +4943,25 @@ UniValue oraclesaddress(const UniValue& params, bool fHelp)
UniValue pricesaddress(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C,*assetscp,C2; std::vector<unsigned char> pubkey; CPubKey mypk,planpk,pricespk; char myaddr[64],houseaddr[64],exposureaddr[64];
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_PRICES);
if ( fHelp || params.size() > 1 )
throw runtime_error("pricesaddress [pubkey]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
if ( params.size() == 1 )
pubkey = ParseHex(params[0].get_str().c_str());
return(CCaddress(cp,(char *)"Prices",pubkey));
result = CCaddress(cp,(char *)"Prices",pubkey);
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(assetscp,myaddr,mypk);
GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk);
GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk);
result.push_back(Pair("myaddr",myaddr)); // for holding my asssets
result.push_back(Pair("houseaddr",houseaddr)); // globally accessible house assets
result.push_back(Pair("exposureaddr",exposureaddr)); // tracking of exposure
return(result);
}
UniValue pegsaddress(const UniValue& params, bool fHelp)
@@ -5106,7 +5139,8 @@ UniValue channelsopen(const UniValue& params, bool fHelp)
throw runtime_error("channelsopen destpubkey numpayments payment\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
destpub = ParseHex(params[0].get_str().c_str());
numpayments = atoi(params[1].get_str().c_str());
payment = atol(params[2].get_str().c_str());
@@ -5127,7 +5161,8 @@ UniValue channelsstop(const UniValue& params, bool fHelp)
throw runtime_error("channelsstop destpubkey origtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
destpub = ParseHex(params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelStop(0,pubkey2pk(destpub),origtxid);
@@ -5147,7 +5182,8 @@ UniValue channelspayment(const UniValue& params, bool fHelp)
throw runtime_error("channelspayment prevtxid origtxid n amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
prevtxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
n = atoi((char *)params[2].get_str().c_str());
@@ -5169,7 +5205,8 @@ UniValue channelscollect(const UniValue& params, bool fHelp)
throw runtime_error("channelscollect paytxid origtxid n amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
paytxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
n = atoi((char *)params[2].get_str().c_str());
@@ -5191,7 +5228,8 @@ UniValue channelsrefund(const UniValue& params, bool fHelp)
throw runtime_error("channelsrefund stoptxid origtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
stoptxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelRefund(0,stoptxid,origtxid);
@@ -5386,6 +5424,188 @@ UniValue rewardsinfo(const UniValue& params, bool fHelp)
return(RewardsInfo(fundingtxid));
}
UniValue gatewayslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
throw runtime_error("gatewayslist\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(GatewaysList());
}
UniValue gatewaysinfo(const UniValue& params, bool fHelp)
{
uint256 txid;
if ( fHelp || params.size() != 1 )
throw runtime_error("gatewaysinfo bindtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
txid = Parseuint256((char *)params[0].get_str().c_str());
return(GatewaysInfo(txid));
}
UniValue gatewaysbind(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector<CPubKey> pubkeys; uint8_t M,N; std::string hex,coin; std::vector<unsigned char> pubkey;
if ( fHelp || params.size() < 6 )
throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
tokenid = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
coin = params[2].get_str();
totalsupply = atol((char *)params[3].get_str().c_str());
M = atoi((char *)params[4].get_str().c_str());
N = atoi((char *)params[5].get_str().c_str());
if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid )
throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n");
for (i=0; i<N; i++)
{
if ( params.size() < 6+i+1 )
throw runtime_error("not enough parameters for N pubkeys\n");
pubkey = ParseHex(params[6+i].get_str().c_str());
pubkeys.push_back(pubkey2pk(pubkey));
}
hex = GatewaysBind(0,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysbind");
return(result);
}
UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int32_t i,claimvout,height; int64_t amount; std::string hex,coin,deposithex; uint256 bindtxid,cointxid; std::vector<uint8_t>proof,destpub,pubkey;
if ( fHelp || params.size() != 9 )
throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
height = atoi((char *)params[1].get_str().c_str());
coin = params[2].get_str();
cointxid = Parseuint256((char *)params[3].get_str().c_str());
claimvout = atoi((char *)params[4].get_str().c_str());
deposithex = params[5].get_str();
proof = ParseHex(params[6].get_str());
destpub = ParseHex(params[7].get_str());
amount = atof((char *)params[8].get_str().c_str()) * COIN;
if ( amount <= 0 || claimvout < 0 )
throw runtime_error("invalid param: amount, numpks or claimvout\n");
hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysdeposit");
return(result);
}
UniValue gatewaysclaim(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex,coin; uint256 bindtxid,deposittxid; std::vector<uint8_t>destpub; int64_t amount;
if ( fHelp || params.size() != 5 )
throw runtime_error("gatewaysclaim bindtxid coin deposittxid destpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
deposittxid = Parseuint256((char *)params[2].get_str().c_str());
destpub = ParseHex(params[3].get_str());
amount = atof((char *)params[4].get_str().c_str()) * COIN;
hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysclaim");
return(result);
}
UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 bindtxid; int64_t amount; std::string hex,coin; std::vector<uint8_t> withdrawpub;
if ( fHelp || params.size() != 4 )
throw runtime_error("gatewayswithdraw bindtxid coin withdrawpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
withdrawpub = ParseHex(params[2].get_str());
amount = atof((char *)params[3].get_str().c_str()) * COIN;
hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewayswithdraw");
return(result);
}
UniValue gatewaysmarkdone(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 withdrawtxid,cointxid; std::string hex,coin;
if ( fHelp || params.size() != 1 )
throw runtime_error("gatewaysmarkdone withdrawtxid coin cointxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
withdrawtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
cointxid = Parseuint256((char *)params[2].get_str().c_str());
hex = GatewaysMarkdone(0,withdrawtxid,coin,cointxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysmarkdone");
return(result);
}
UniValue gatewayspending(const UniValue& params, bool fHelp)
{
uint256 bindtxid; std::string coin;
if ( fHelp || params.size() != 2 )
throw runtime_error("gatewayspending bindtxid coin\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
return(GatewaysPendingWithdraws(bindtxid,coin));
}
UniValue gatewaysmultisig(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 bindtxid,withtxid; std::string coin,hex; char *txidaddr;
if ( fHelp || params.size() != 2 )
throw runtime_error("gatewaysmultisig bindtxid coin withtxid txidaddr\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
withtxid = Parseuint256((char *)params[2].get_str().c_str());
txidaddr = (char *)params[3].get_str().c_str();
hex = GatewaysMultisig(0,coin,bindtxid,withtxid,txidaddr);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex",hex));
} else ERR_RESULT("couldnt gatewaysmultisig");
return(result);
}
UniValue oracleslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
@@ -5413,6 +5633,8 @@ UniValue oraclesregister(const UniValue& params, bool fHelp)
throw runtime_error("oraclesregister oracletxid datafee\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
datafee = atol((char *)params[1].get_str().c_str());
hex = OracleRegister(0,txid,datafee);
@@ -5431,6 +5653,8 @@ UniValue oraclessubscribe(const UniValue& params, bool fHelp)
throw runtime_error("oraclessubscribe oracletxid publisher amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
pubkey = ParseHex(params[1].get_str().c_str());
amount = atof((char *)params[2].get_str().c_str()) * COIN;
@@ -5463,6 +5687,8 @@ UniValue oraclesdata(const UniValue& params, bool fHelp)
throw runtime_error("oraclesdata oracletxid hexstr\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
data = ParseHex(params[1].get_str().c_str());
hex = OracleData(0,txid,data);
@@ -5599,6 +5825,156 @@ UniValue faucetget(const UniValue& params, bool fHelp)
return(result);
}
UniValue priceslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
throw runtime_error("priceslist\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(PricesList());
}
UniValue pricesinfo(const UniValue& params, bool fHelp)
{
uint256 fundingtxid;
if ( fHelp || params.size() != 1 )
throw runtime_error("pricesinfo fundingtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
return(PricesInfo(fundingtxid));
}
UniValue pricescreate(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint64_t mode; int64_t funding; int32_t i,n,margin,maxleverage; std::string hex; uint256 oracletxid,longtoken,shorttoken,bettoken; std::vector<CPubKey> pubkeys; std::vector<uint8_t>pubkey;
if ( fHelp || params.size() < 8 )
throw runtime_error("pricescreate bettoken oracletxid margin mode longtoken shorttoken maxleverage funding N [pubkeys]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bettoken = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
margin = atof(params[2].get_str().c_str()) * 1000;
mode = atol(params[3].get_str().c_str());
longtoken = Parseuint256((char *)params[4].get_str().c_str());
shorttoken = Parseuint256((char *)params[5].get_str().c_str());
maxleverage = atol(params[6].get_str().c_str());
funding = atof(params[7].get_str().c_str()) * COIN;
n = atoi(params[8].get_str().c_str());
if ( n > 0 )
{
for (i=0; i<n; i++)
{
if ( params.size() < 9+i+1 )
throw runtime_error("not enough parameters for N pubkeys\n");
pubkey = ParseHex(params[9+i].get_str().c_str());
pubkeys.push_back(pubkey2pk(pubkey));
}
}
hex = PricesCreateFunding(0,bettoken,oracletxid,margin,mode,longtoken,shorttoken,maxleverage,funding,pubkeys);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create prices funding transaction");
}
return(result);
}
UniValue pricesaddfunding(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesaddfunding fundingtxid bettoken amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN;
hex = PricesAddFunding(0,bettoken,fundingtxid,amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesaddfunding transaction");
}
return(result);
}
UniValue pricesbet(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount; int32_t leverage;
if ( fHelp || params.size() != 4 )
throw runtime_error("pricesbet fundingtxid bettoken amount leverage\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN;
leverage = atoi(params[3].get_str().c_str());
hex = PricesBet(0,bettoken,fundingtxid,amount,leverage);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesbet transaction");
}
return(result);
}
UniValue pricesstatus(const UniValue& params, bool fHelp)
{
uint256 fundingtxid,bettxid,bettoken;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesstatus fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
return(PricesStatus(0,bettoken,fundingtxid,bettxid));
}
UniValue pricesfinish(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 fundingtxid,bettxid,bettoken; std::string hex;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesfinish fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
hex = PricesFinish(0,bettoken,fundingtxid,bettxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesfinish transaction");
}
return(result);
}
UniValue dicefund(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name;
@@ -5773,7 +6149,6 @@ UniValue dicestatus(const UniValue& params, bool fHelp)
UniValue dicelist(const UniValue& params, bool fHelp)
{
uint256 tokenid;
if ( fHelp || params.size() > 0 )
throw runtime_error("dicelist\n");
if ( ensure_CCrequirements() < 0 )
@@ -5922,6 +6297,42 @@ UniValue tokentransfer(const UniValue& params, bool fHelp)
return(result);
}
UniValue tokenconvert(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; int32_t evalcode; int64_t amount; uint256 tokenid;
if ( fHelp || params.size() != 4 )
throw runtime_error("tokenconvert evalcode tokenid pubkey amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
evalcode = atoi(params[0].get_str().c_str());
tokenid = Parseuint256((char *)params[1].get_str().c_str());
std::vector<unsigned char> pubkey(ParseHex(params[2].get_str().c_str()));
amount = atol(params[3].get_str().c_str());
if ( tokenid == zeroid )
{
ERR_RESULT("invalid tokenid");
return(result);
}
if ( amount <= 0 )
{
ERR_RESULT("amount must be positive");
return(result);
}
hex = AssetConvert(0,tokenid,pubkey,amount,evalcode);
if (amount > 0) {
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt convert tokens");
} else {
ERR_RESULT("amount must be positive");
}
return(result);
}
UniValue tokenbid(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;

View File

@@ -2121,7 +2121,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
{
if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME )
{
LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
//LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
continue;
}
}