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 }