github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/walletapi/rpc_transfersplit.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package walletapi
    18  
    19  import "fmt"
    20  import "context"
    21  import "encoding/hex"
    22  import "encoding/json"
    23  
    24  //import	"log"
    25  //import 	"net/http"
    26  
    27  import "github.com/romana/rlog"
    28  import "github.com/intel-go/fastjson"
    29  import "github.com/osamingo/jsonrpc"
    30  
    31  import "github.com/deroproject/derosuite/globals"
    32  import "github.com/deroproject/derosuite/address"
    33  import "github.com/deroproject/derosuite/structures"
    34  
    35  type TransferSplit_Handler struct { // this has access to the wallet
    36  	r *RPCServer
    37  }
    38  
    39  func (h TransferSplit_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
    40  
    41  	var p structures.TransferSplit_Params
    42  	var result structures.TransferSplit_Result
    43  	var err error
    44  
    45  	h.r.Lock()
    46  	defer h.r.Unlock()
    47  	rlog.Debugf("transfer split handler")
    48  	defer rlog.Debugf("transfer split handler finished")
    49  
    50  	if errp := jsonrpc.Unmarshal(params, &p); err != nil {
    51  		rlog.Errorf("Could not parse incoming json, err %s\n", errp)
    52  		return nil, errp
    53  	}
    54  
    55  	//if len(p.Destinations) < 1 || p.Mixin < 4 {
    56  	//    return nil, jsonrpc.ErrInvalidParams()
    57  	//}
    58  
    59  	rlog.Debugf("Len destinations %d %+v", len(p.Destinations), p)
    60  
    61          unlock_time := p.Unlock_time
    62  	payment_id := p.Payment_ID
    63  	if len(payment_id) > 0 && (len(payment_id) == 64 || len(payment_id) == 16) != true  {
    64  		return nil, jsonrpc.ErrInvalidParams() // we should give invalid payment ID
    65  	}
    66  	if _, err := hex.DecodeString(p.Payment_ID); err != nil {
    67  		return nil, jsonrpc.ErrInvalidParams() // we should give invalid payment ID
    68  	}
    69  	rlog.Debugf("Payment ID %s", payment_id)
    70  
    71  	b, err := json.Marshal(p)
    72  	if err == nil {
    73  		rlog.Debugf("Request can be repeated using below command")
    74  
    75  		rlog.Debugf(`curl -X POST http://127.0.0.1:18092/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"transfer_split","params":%s}' -H 'Content-Type: application/json'`, string(b))
    76  	}
    77  
    78  	var address_list []address.Address
    79  	var amount_list []uint64
    80  	for i := range p.Destinations {
    81  		a, err := globals.ParseValidateAddress(p.Destinations[i].Address)
    82  		if err != nil {
    83  			rlog.Errorf("Parsing address failed %s err %s\n", p.Destinations[i].Address, err)
    84  			return nil, jsonrpc.ErrInvalidParams()
    85  		}
    86  		address_list = append(address_list, *a)
    87  		amount_list = append(amount_list, p.Destinations[i].Amount)
    88  
    89  	}
    90  
    91  	fees_per_kb := uint64(0) // fees  must be calculated by walletapi
    92  	if !h.r.w.GetMode() {    // if wallet is in online mode, use the fees, provided by the daemon, else we need to use what is provided by the user
    93  
    94  		// TODO
    95  	}
    96  	tx, inputs, input_sum, change, err := h.r.w.Transfer(address_list, amount_list, unlock_time, payment_id, fees_per_kb, p.Mixin)
    97  	_ = inputs
    98  	if err != nil {
    99  		rlog.Warnf("Error while building Transaction err %s\n", err)
   100  		return nil, &jsonrpc.Error{Code: -2, Message: fmt.Sprintf("Error while building Transaction err %s", err)}
   101  
   102  	}
   103  
   104  	rlog.Infof("Inputs Selected for %s \n", globals.FormatMoneyPrecision(input_sum, 12))
   105  	amount := uint64(0)
   106  	for i := range amount_list {
   107  		amount += amount_list[i]
   108  	}
   109  	rlog.Infof("Transfering total amount %s \n", globals.FormatMoneyPrecision(amount, 12))
   110  	rlog.Infof("change amount ( will come back ) %s \n", globals.FormatMoneyPrecision(change, 12))
   111  	rlog.Infof("fees %s \n", globals.FormatMoneyPrecision(tx.RctSignature.Get_TX_Fee(), 12))
   112  
   113  	if input_sum != (amount + change + tx.RctSignature.Get_TX_Fee()) {
   114  		panic(fmt.Sprintf("Inputs %d != outputs ( %d + %d + %d )", input_sum, amount, change, tx.RctSignature.Get_TX_Fee()))
   115  	}
   116  
   117  	if p.Do_not_relay == false { // we do not relay the tx, the user must submit it manually
   118  		err = h.r.w.SendTransaction(tx)
   119  
   120  		if err == nil {
   121  			rlog.Infof("Transaction sent successfully. txid = %s", tx.GetHash())
   122  		} else {
   123  			rlog.Warnf("Transaction sending failed txid = %s, err %s", tx.GetHash(), err)
   124  			return nil, &jsonrpc.Error{Code: -2, Message: fmt.Sprintf("Transaction sending failed txid = %s, err %s", tx.GetHash(), err)}
   125  		}
   126  
   127  	}
   128  
   129  	result.Fee_list = append(result.Fee_list, tx.RctSignature.Get_TX_Fee())
   130  	result.Tx_hash_list = append(result.Tx_hash_list, tx.GetHash().String())
   131  	if p.Get_tx_hex { // request need TX blobs, give them
   132  		result.Tx_blob_list = append(result.Tx_blob_list, hex.EncodeToString(tx.SerializeHeader()))
   133  	}
   134  	//
   135  	//extract secret key and feed it in here
   136  	if p.Get_tx_key {
   137  		result.Tx_key_list = append(result.Tx_key_list, h.r.w.GetTXKey(tx.GetHash())) //TODO
   138  	}
   139  
   140  	return result, nil
   141  }