V1 Resolution example (go)
The following Go code and example command-line application demonstrates how to efficiently resolve the smart-signature account address for a name, or an address on-chain.
This code is only for NFDs registered prior to the deployment of the 2.x NFD registry.
/*
* Copyright (c) 2022. TxnLab Inc.
* All Rights reserved.
*/
package main
import (
"bytes"
"encoding/binary"
"errors"
"flag"
"fmt"
"log"
"reflect"
"github.com/algorand/go-algorand-sdk/crypto"
"github.com/algorand/go-algorand-sdk/types"
)
func main() {
var (
lsig crypto.LogicSigAccount
lsigAddr types.Address
err error
)
name := flag.String("name", "", ".Algo Name for forward lookup - invalid names can be passed here but would never be allowed to be minted...")
address := flag.String("addr", "", "Algorand address for reverse-address lookup")
regAppID := flag.Uint64("id", 760937186, "Registry application id (mainnet defaulted)")
flag.Parse()
if *name == "" && *address == "" {
flag.Usage()
log.Fatalln("You must specify a name, or an address")
}
if *name != "" {
lsig, err = GetNFDSigNameLSIG(*name, *regAppID)
}
if *address != "" {
addr, err := types.DecodeAddress(*address)
if err != nil {
log.Fatalln("Error decoding algoand address parameter:", err)
}
lsig, err = GetNFDSigRevAddressLSIG(addr, *regAppID)
}
if err != nil {
log.Fatalln("error in lsig calculation:", err)
}
lsigAddr, err = lsig.Address()
if err != nil {
log.Fatalln(err)
}
fmt.Println("Registration account:", lsigAddr.String())
}
func getLookupLSIG(prefixBytes, lookupBytes string, registryAppID uint64) (crypto.LogicSigAccount, error) {
/*
#pragma version 5
intcblock 1
pushbytes 0x0102030405060708
btoi
store 0
txn ApplicationID
load 0
==
txn TypeEnum
pushint 6
==
&&
txn OnCompletion
intc_0 // 1
==
txn OnCompletion
pushint 0
==
||
&&
bnz label1
err
label1:
intc_0 // 1
return
bytecblock "xxx"
*/
sigLookupByteCode := []byte{
0x05, 0x20, 0x01, 0x01, 0x80, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x17, 0x35, 0x00, 0x31, 0x18, 0x34, 0x00, 0x12, 0x31, 0x10,
0x81, 0x06, 0x12, 0x10, 0x31, 0x19, 0x22, 0x12, 0x31, 0x19, 0x81, 0x00,
0x12, 0x11, 0x10, 0x40, 0x00, 0x01, 0x00, 0x22, 0x43, 0x26, 0x01,
}
contractSlice := sigLookupByteCode[6:14]
if !reflect.DeepEqual(contractSlice, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}) {
return crypto.LogicSigAccount{}, errors.New("Lookup template doesn't match expectation")
}
// Bytes 6-13 [0-index] with 0x01-0x08 placeholders is where we put the Registry Contract App ID bytes in big-endian
binary.BigEndian.PutUint64(contractSlice, registryAppID)
// We then 'append' the bytes of the prefix + lookup to the end in a bytecblock chunk
// ie: name/patrick.algo, or address/RXZRFW26WYHFV44APFAK4BEMU3P54OBK47LCAZQJPXOTZ4AZPSFDAKLIQY
// - the 0x26 0x01 at end of sigLookupByteCode is the bytecblock opcode and specifying a single value is being added
// We write the uvarint length of our lookup bytes.. then append the bytes of that lookpup string..
bytesToAppend := bytes.Join([][]byte{[]byte(prefixBytes), []byte(lookupBytes)}, nil)
uvarIntBytes := make([]byte, binary.MaxVarintLen64)
nBytes := binary.PutUvarint(uvarIntBytes, uint64(len(bytesToAppend)))
composedBytecode := bytes.Join([][]byte{sigLookupByteCode, uvarIntBytes[:nBytes], bytesToAppend}, nil)
logicSig := crypto.MakeLogicSigAccountEscrow(composedBytecode, [][]byte{})
return logicSig, nil
}
func GetNFDSigNameLSIG(nfdName string, registryAppID uint64) (crypto.LogicSigAccount, error) {
return getLookupLSIG("name/", nfdName, registryAppID)
}
func GetNFDSigRevAddressLSIG(pointedToAddress types.Address, registryAppID uint64) (crypto.LogicSigAccount, error) {
return getLookupLSIG("address/", pointedToAddress.String(), registryAppID)
}
To be clear, this "lookup" is a hash to get to an Algorand account that may contain state. It does not mean data exists there at the moment.
Last updated