github.com/algorand/go-algorand-sdk@v1.24.0/templates/periodicPayment.go (about)

     1  package templates
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  
     7  	"github.com/algorand/go-algorand-sdk/crypto"
     8  	"github.com/algorand/go-algorand-sdk/future"
     9  	"github.com/algorand/go-algorand-sdk/logic"
    10  	"github.com/algorand/go-algorand-sdk/types"
    11  	"golang.org/x/crypto/ed25519"
    12  )
    13  
    14  // PeriodicPayment template representation
    15  //
    16  // Deprecated: Use TealCompile source compilation instead.
    17  type PeriodicPayment struct {
    18  	ContractTemplate
    19  }
    20  
    21  // GetPeriodicPaymentWithdrawalTransaction returns a signed transaction extracting funds from the contract
    22  // contract: the bytearray defining the contract, received from the payer
    23  // firstValid: the first round on which the txn will be valid
    24  // fee: the fee in microalgos per byte of the payment txn
    25  // genesisHash: the hash representing the network for the txn
    26  //
    27  // Deprecated: Use TealCompile source compilation instead.
    28  func GetPeriodicPaymentWithdrawalTransaction(contract []byte, firstValid, fee uint64, genesisHash []byte) ([]byte, error) {
    29  	address := crypto.AddressFromProgram(contract)
    30  	ints, byteArrays, err := logic.ReadProgram(contract, nil)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	contractLease := byteArrays[0]
    35  	// Convert the byteArrays[1] to receiver
    36  	var receiver types.Address
    37  	n := copy(receiver[:], byteArrays[1])
    38  	if n != ed25519.PublicKeySize {
    39  		return nil, fmt.Errorf("address generated from receiver bytes is the wrong size")
    40  	}
    41  	period, withdrawWindow, amount := ints[2], ints[4], ints[5]
    42  	if firstValid%period != 0 {
    43  		return nil, fmt.Errorf("firstValid round %d was not a multiple of the contract period %d", firstValid, period)
    44  	}
    45  	lastValid := firstValid + withdrawWindow
    46  	params := types.SuggestedParams{
    47  		Fee:             types.MicroAlgos(fee),
    48  		GenesisHash:     genesisHash,
    49  		FirstRoundValid: types.Round(firstValid),
    50  		LastRoundValid:  types.Round(lastValid),
    51  		FlatFee:         false,
    52  	}
    53  	txn, err := future.MakePaymentTxn(address.String(), receiver.String(), amount, nil, "", params)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	lease := [32]byte{}
    58  	copy(lease[:], contractLease) // convert from []byte to [32]byte
    59  	txn.AddLease(lease, fee)
    60  
    61  	logicSig, err := crypto.MakeLogicSig(contract, nil, nil, crypto.MultisigAccount{})
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	_, signedTxn, err := crypto.SignLogicsigTransaction(logicSig, txn)
    66  	return signedTxn, err
    67  }
    68  
    69  // MakePeriodicPayment allows some account to execute periodic withdrawal of funds.
    70  // This is a contract account.
    71  //
    72  // This allows receiver to withdraw amount every
    73  // period rounds for withdrawWindow after every multiple
    74  // of period.
    75  //
    76  // After expiryRound, all remaining funds in the escrow
    77  // are available to receiver.
    78  //
    79  // Parameters:
    80  //  - receiver: address which is authorized to receive withdrawals
    81  //  - amount: the maximum number of funds allowed for a single withdrawal
    82  //  - withdrawWindow: the duration of a withdrawal period
    83  //  - period: the time between a pair of withdrawal periods
    84  //  - expiryRound: the round at which the account expires
    85  //  - maxFee: maximum fee used by the withdrawal transaction
    86  //
    87  // Deprecated: Use TealCompile source compilation instead.
    88  func MakePeriodicPayment(receiver string, amount, withdrawWindow, period, expiryRound, maxFee uint64) (PeriodicPayment, error) {
    89  	leaseBytes := make([]byte, 32)
    90  	crypto.RandomBytes(leaseBytes)
    91  	leaseString := base64.StdEncoding.EncodeToString(leaseBytes)
    92  	return makePeriodicPaymentWithLease(receiver, leaseString, amount, withdrawWindow, period, expiryRound, maxFee)
    93  }
    94  
    95  // makePeriodicPaymentWithLease is as MakePeriodicPayment, but the caller can specify the lease (using b64 string)
    96  func makePeriodicPaymentWithLease(receiver, lease string, amount, withdrawWindow, period, expiryRound, maxFee uint64) (PeriodicPayment, error) {
    97  	const referenceProgram = "ASAHAQYFAAQDByYCIAECAwQFBgcIAQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIIJKvkYTkEzwJf2arzJOxERsSogG9nQzKPkpIoc4TzPTFMRAiEjEBIw4QMQIkGCUSEDEEIQQxAggSEDEGKBIQMQkyAxIxBykSEDEIIQUSEDEJKRIxBzIDEhAxAiEGDRAxCCUSEBEQ"
    98  	referenceAsBytes, err := base64.StdEncoding.DecodeString(referenceProgram)
    99  	if err != nil {
   100  		return PeriodicPayment{}, err
   101  	}
   102  	receiverAddr, err := types.DecodeAddress(receiver)
   103  	if err != nil {
   104  		return PeriodicPayment{}, err
   105  	}
   106  
   107  	var referenceOffsets = []uint64{ /*fee*/ 4 /*period*/, 5 /*withdrawWindow*/, 7 /*amount*/, 8 /*expiryRound*/, 9 /*lease*/, 12 /*receiver*/, 46}
   108  	injectionVector := []interface{}{maxFee, period, withdrawWindow, amount, expiryRound, lease, receiverAddr}
   109  	injectedBytes, err := inject(referenceAsBytes, referenceOffsets, injectionVector)
   110  	if err != nil {
   111  		return PeriodicPayment{}, err
   112  	}
   113  
   114  	address := crypto.AddressFromProgram(injectedBytes)
   115  	periodicPayment := PeriodicPayment{
   116  		ContractTemplate: ContractTemplate{
   117  			address: address.String(),
   118  			program: injectedBytes,
   119  		},
   120  	}
   121  	return periodicPayment, err
   122  }