github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/shared/voucher.go (about)

     1  package shared
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/ethereum/go-ethereum/rlp"
    11  )
    12  
    13  ///////////////////
    14  // Voucher Structs
    15  ///////////////////
    16  
    17  type ProposalKey struct {
    18  	Address     string `json:"address"`
    19  	KeyId       uint   `json:"keyId"`
    20  	SequenceNum uint   `json:"sequenceNum"`
    21  }
    22  type PayloadSig struct {
    23  	Address string `json:"address"`
    24  	KeyId   uint   `json:"keyId"`
    25  	Sig     string `json:"sig"`
    26  }
    27  type Voucher struct {
    28  	Cadence      string              `json:"cadence"`
    29  	RefBlock     string              `json:"refBlock"`
    30  	ComputeLimit uint                `json:"computeLimit"`
    31  	Arguments    []map[string]string `json:"arguments"`
    32  	Payer        string              `json:"payer"`
    33  	Authorizers  []string            `json:"authorizers"`
    34  	ProposalKey  ProposalKey         `json:"proposalKey"`
    35  	PayloadSigs  []PayloadSig        `json:"payloadSigs"`
    36  	EnvelopeSigs []PayloadSig        `json:"envelopeSigs"`
    37  }
    38  
    39  func rightPaddedBuffer(s string, numBytes uint) string {
    40  	format := "%-" + fmt.Sprintf("%d", numBytes*2) + "s"
    41  	_rightPaddedStr := fmt.Sprintf(format, s)
    42  	rightPaddedStr := strings.Replace(_rightPaddedStr, " ", "0", int(numBytes*2))
    43  	return rightPaddedStr
    44  }
    45  func leftPaddedBuffer(s string, numBytes uint) []byte {
    46  	format := "%0" + fmt.Sprintf("%d", numBytes*2) + "s"
    47  	leftPaddedStr := fmt.Sprintf(format, s)
    48  	data, _ := hex.DecodeString(leftPaddedStr)
    49  	return data
    50  }
    51  func blockBuffer(s string) []byte {
    52  	return leftPaddedBuffer(s, 32)
    53  }
    54  func addressBuffer(s string) []byte {
    55  	return leftPaddedBuffer(s, 8)
    56  }
    57  func sansPrefix(addr string) string {
    58  	return strings.TrimPrefix(addr, "0x")
    59  }
    60  func rlpEncode(p interface{}) string {
    61  	b := new(bytes.Buffer)
    62  	_ = rlp.Encode(b, p)
    63  	return hex.EncodeToString(b.Bytes())
    64  }
    65  
    66  func EncodeMessageFromVoucher(v *Voucher) string {
    67  	var toEncode []interface{}
    68  
    69  	// CADENCE
    70  	toEncode = append(toEncode, v.Cadence)
    71  
    72  	// ARGUMENTS
    73  	// Stringify tx args
    74  	args := make([]string, len(v.Arguments))
    75  	for i, arg := range v.Arguments {
    76  		jsonStrArg, _ := json.Marshal(arg)
    77  		args[i] = string(jsonStrArg)
    78  	}
    79  	toEncode = append(toEncode, args)
    80  
    81  	// REF BLOCK
    82  	toEncode = append(toEncode, blockBuffer(v.RefBlock))
    83  
    84  	// COMPUTE LIMIT
    85  	toEncode = append(toEncode, v.ComputeLimit)
    86  
    87  	// PROPOSAL KEY ADDRESS
    88  	proposalAddrData := addressBuffer(sansPrefix(v.ProposalKey.Address))
    89  	toEncode = append(toEncode, proposalAddrData)
    90  
    91  	// PROPOSAL KEY ID
    92  	toEncode = append(toEncode, v.ProposalKey.KeyId)
    93  
    94  	// PROPOSAL KEY SEQ NUM
    95  	toEncode = append(toEncode, v.ProposalKey.SequenceNum)
    96  
    97  	// PAYER
    98  	payerData := leftPaddedBuffer(sansPrefix(v.Payer), 8)
    99  	toEncode = append(toEncode, payerData) // 8 bytes left padded w/ 0s
   100  
   101  	// AUTHORIZERS
   102  	authorizers := make([][]byte, len(v.Authorizers))
   103  	// pad authorizer addresses
   104  	for i, addr := range v.Authorizers {
   105  		authorizers[i] = addressBuffer(sansPrefix(addr))
   106  	}
   107  	toEncode = append(toEncode, authorizers)
   108  
   109  	// We only want to generate the message signed by the user.
   110  	//
   111  	// If wallet is custodial, then the user will sign the tx payload
   112  	// and the custodian will sign the envelope. In this case, only generate
   113  	// the encoded tx payload, i.e. the message signed by the user.
   114  	//
   115  	// If wallet is non-custodial, the user only needs to sign the envelope, so
   116  	// payloadSigs will be empty.  In this case, generate the encoded tx envelope,
   117  	// i.e. the message signed by the user
   118  	if len(v.PayloadSigs) > 0 {
   119  		// Go straight to envelope payload if there are no payload sigs
   120  		return rlpEncode(toEncode)
   121  
   122  	} else {
   123  		// Encode Transaction Envelope:
   124  		// If payload sigs are present, only encode the payload message/sig, not the envelope
   125  		// - create new array to rlpEncode using transaction Payload and payload sigs
   126  		var envelopePayloadToEncode []interface{}
   127  		envelopePayloadToEncode = append(envelopePayloadToEncode, toEncode)
   128  		envelopePayloadToEncode = append(envelopePayloadToEncode, v.PayloadSigs)
   129  		envelopePayload := rlpEncode(envelopePayloadToEncode)
   130  		return envelopePayload
   131  	}
   132  }
   133  
   134  // Non-custodial wallets will only contain one signer, so payloadSigs
   135  // will be empty, and only the envelope will be signed.
   136  // For Custodial wallets (Blocto/Dapper), the user signs the tx payload
   137  // and envelope is signed by custodian.
   138  //
   139  // This function returns only the signature generated by the user
   140  func GetUserCompositeSignatureFromVoucher(v *Voucher) *[]CompositeSignature {
   141  	var compositeSig CompositeSignature
   142  	if len(v.PayloadSigs) > 0 {
   143  		compositeSig = CompositeSignature{
   144  			Addr:      v.PayloadSigs[0].Address,
   145  			Key_id:    v.PayloadSigs[0].KeyId,
   146  			Signature: v.PayloadSigs[0].Sig,
   147  		}
   148  	} else {
   149  		compositeSig = CompositeSignature{
   150  			Addr:      v.EnvelopeSigs[0].Address,
   151  			Key_id:    v.EnvelopeSigs[0].KeyId,
   152  			Signature: v.EnvelopeSigs[0].Sig,
   153  		}
   154  	}
   155  
   156  	return &[]CompositeSignature{compositeSig}
   157  }