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 }