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

     1  package templates
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"github.com/algorand/go-algorand-sdk/types"
     9  )
    10  
    11  // ContractTemplate template representation
    12  //
    13  // Deprecated: Use TealCompile source compilation instead.
    14  type ContractTemplate struct {
    15  	address string
    16  	program []byte
    17  }
    18  
    19  // GetAddress returns the contract address
    20  func (contract ContractTemplate) GetAddress() string {
    21  	return contract.address
    22  }
    23  
    24  // GetProgram returns the program bytes
    25  func (contract ContractTemplate) GetProgram() []byte {
    26  	return contract.program
    27  }
    28  
    29  func replace(buf, newBytes []byte, offset, placeholderLength uint64) []byte {
    30  	firstChunk := make([]byte, len(buf[:offset]))
    31  	copy(firstChunk, buf[:offset])
    32  	firstChunkAmended := append(firstChunk, newBytes...)
    33  	secondChunk := make([]byte, len(buf[(offset+placeholderLength):]))
    34  	copy(secondChunk, buf[(offset+placeholderLength):])
    35  	return append(firstChunkAmended, secondChunk...)
    36  }
    37  
    38  func inject(original []byte, offsets []uint64, values []interface{}) (result []byte, err error) {
    39  	result = original
    40  	if len(offsets) != len(values) {
    41  		err = fmt.Errorf("length of offsets %v does not match length of replacement values %v", len(offsets), len(values))
    42  		return
    43  	}
    44  
    45  	for i, value := range values {
    46  		decodedLength := 0
    47  		if valueAsUint, ok := value.(uint64); ok {
    48  			// make the exact minimum buffer needed and no larger
    49  			// because otherwise there will be extra bytes inserted
    50  			sizingBuffer := make([]byte, binary.MaxVarintLen64)
    51  			decodedLength = binary.PutUvarint(sizingBuffer, valueAsUint)
    52  			fillingBuffer := make([]byte, decodedLength)
    53  			decodedLength = binary.PutUvarint(fillingBuffer, valueAsUint)
    54  			result = replace(result, fillingBuffer, offsets[i], uint64(1))
    55  		} else if address, ok := value.(types.Address); ok {
    56  			addressLen := uint64(32)
    57  			addressBytes := make([]byte, addressLen)
    58  			copy(addressBytes, address[:])
    59  			result = replace(result, addressBytes, offsets[i], addressLen)
    60  		} else if b64string, ok := value.(string); ok {
    61  			decodeBytes, decodeErr := base64.StdEncoding.DecodeString(b64string)
    62  			if decodeErr != nil {
    63  				err = decodeErr
    64  				return
    65  			}
    66  			// do the same thing as in the uint64 case to trim empty bytes:
    67  			// first fill one buffer to figure out the number of bytes to be written,
    68  			// then fill a second buffer of exactly the right size
    69  			sizingBuffer := make([]byte, binary.MaxVarintLen64)
    70  			numBytesWritten := binary.PutUvarint(sizingBuffer, uint64(len(decodeBytes)))
    71  			fillingBuffer := make([]byte, numBytesWritten)
    72  			binary.PutUvarint(fillingBuffer, uint64(len(decodeBytes))) // indicate length of b64 bytes
    73  			// want to write [length of b64 bytes, b64 bytes]
    74  			decodeBytes = append(fillingBuffer, decodeBytes...)
    75  			result = replace(result, decodeBytes, offsets[i], uint64(33))
    76  		}
    77  
    78  		if decodedLength != 0 {
    79  			for j := range offsets {
    80  				offsets[j] = offsets[j] + uint64(decodedLength) - 1
    81  			}
    82  		}
    83  	}
    84  	return
    85  }