1// Package txlink provides utilities for creating transaction-related links2// compatible with Gnoweb, Gnobro, and other clients within the Gno ecosystem.3//4// This package is optimized for generating lightweight transaction links with5// flexible arguments, allowing users to build dynamic links that integrate6// seamlessly with various Gno clients.7//8// The package offers a way to generate clickable transaction MD links9// for the current "relative realm":10//11// Using a builder pattern for more structured URLs:12// txlink.NewLink("MyFunc").13// AddArgs("k1", "v1", "k2", "v2"). // or multiple at once14// SetSend("1000000ugnot").15// URL()16//17// The builder pattern (TxBuilder) provides a fluent interface for constructing18// transaction URLs in the current "relative realm". Like Call, it supports both19// local realm paths and fully qualified paths through the underlying Call20// implementation.21//22// The Call function remains the core implementation, used both directly and23// internally by the builder pattern to generate the final URLs.24//25// This package is a streamlined alternative to helplink, providing similar26// functionality for transaction links without the full feature set of helplink.2728package txlink2930import (31 "chain/runtime"32 "chain/runtime/unsafe"33 "net/url"34 "strings"35)3637var chainDomain = runtime.ChainDomain()3839// Realm represents a specific realm for generating tx links.40type Realm string4142// TxBuilder provides a fluent interface for building transaction URLs43type TxBuilder struct {44 fn string // function name45 args []string // key-value pairs46 send string // optional send amount47 realm_XXX Realm // realm for the URL48}4950// NewLink creates a transaction link builder for the specified function in the current realm.51func NewLink(fn string) *TxBuilder {52 return Realm("").NewLink(fn)53}5455// NewLink creates a transaction link builder for the specified function in this realm.56func (r Realm) NewLink(fn string) *TxBuilder {57 if fn == "" {58 return nil59 }60 return &TxBuilder{fn: fn, realm_XXX: r}61}6263// addArg adds a key-value argument pair. Returns the builder for chaining.64func (b *TxBuilder) addArg(key, value string) *TxBuilder {65 if b == nil {66 return nil67 }68 if key == "" {69 return b70 }7172 // Special case: "." prefix is for reserved keywords.73 if strings.HasPrefix(key, ".") {74 panic("invalid key")75 }7677 b.args = append(b.args, key, value)78 return b79}8081// AddArgs adds multiple key-value pairs at once. Arguments should be provided82// as pairs: AddArgs("key1", "value1", "key2", "value2").83func (b *TxBuilder) AddArgs(args ...string) *TxBuilder {84 if b == nil {85 return nil86 }87 if len(args)%2 != 0 {88 panic("odd number of arguments")89 }90 // Add key-value pairs91 for i := 0; i < len(args); i += 2 {92 key := args[i]93 value := args[i+1]94 b.addArg(key, value)95 }96 return b97}9899// SetSend adds a send amount. (Only one send amount can be specified.)100func (b *TxBuilder) SetSend(amount string) *TxBuilder {101 if b == nil {102 return nil103 }104 if amount == "" {105 return b106 }107 b.send = amount108 return b109}110111// URL generates the final URL using the standard $help&func=name format.112func (b *TxBuilder) URL() string {113 if b == nil || b.fn == "" {114 return ""115 }116 args := b.args117 if b.send != "" {118 args = append(args, ".send", b.send)119 }120 return b.realm_XXX.Call(b.fn, args...)121}122123// Call returns a URL for the specified function with optional key-value124// arguments, for the current realm.125func Call(fn string, args ...string) string {126 return Realm("").Call(fn, args...)127}128129// prefix returns the URL prefix for the realm.130func (r Realm) prefix() string {131 // relative132 if r == "" {133 curPath := unsafe.CurrentRealm().PkgPath()134 return strings.TrimPrefix(curPath, chainDomain)135 }136137 // local realm -> /realm138 rlm := string(r)139 if strings.HasPrefix(rlm, chainDomain) {140 return strings.TrimPrefix(rlm, chainDomain)141 }142143 // remote realm -> https://remote.land/realm144 return "https://" + string(r)145}146147// Call returns a URL for the specified function with optional key-value148// arguments.149func (r Realm) Call(fn string, args ...string) string {150 if len(args) == 0 {151 return r.prefix() + "$help&func=" + fn152 }153154 // Create url.Values to properly encode parameters.155 // But manage &func=fn as a special case to keep it as the first argument.156 values := url.Values{}157158 // Check if args length is even159 if len(args)%2 != 0 {160 panic("odd number of arguments")161 }162 // Add key-value pairs to values163 for i := 0; i < len(args); i += 2 {164 key := args[i]165 value := args[i+1]166 values.Add(key, value)167 }168169 // Build the base URL and append encoded query parameters170 return r.prefix() + "$help&func=" + fn + "&" + values.Encode()171}172Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.