Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

txlink.gno

4.59 Kb · 171 lines
  1// Package txlink provides utilities for creating transaction-related links
  2// compatible with Gnoweb, Gnobro, and other clients within the Gno ecosystem.
  3//
  4// This package is optimized for generating lightweight transaction links with
  5// flexible arguments, allowing users to build dynamic links that integrate
  6// seamlessly with various Gno clients.
  7//
  8// The package offers a way to generate clickable transaction MD links
  9// 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 once
 14//         SetSend("1000000ugnot").
 15//         URL()
 16//
 17// The builder pattern (TxBuilder) provides a fluent interface for constructing
 18// transaction URLs in the current "relative realm". Like Call, it supports both
 19// local realm paths and fully qualified paths through the underlying Call
 20// implementation.
 21//
 22// The Call function remains the core implementation, used both directly and
 23// internally by the builder pattern to generate the final URLs.
 24//
 25// This package is a streamlined alternative to helplink, providing similar
 26// functionality for transaction links without the full feature set of helplink.
 27
 28package txlink
 29
 30import (
 31	"chain/runtime"
 32	"chain/runtime/unsafe"
 33	"net/url"
 34	"strings"
 35)
 36
 37var chainDomain = runtime.ChainDomain()
 38
 39// Realm represents a specific realm for generating tx links.
 40type Realm string
 41
 42// TxBuilder provides a fluent interface for building transaction URLs
 43type TxBuilder struct {
 44	fn        string   // function name
 45	args      []string // key-value pairs
 46	send      string   // optional send amount
 47	realm_XXX Realm    // realm for the URL
 48}
 49
 50// 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}
 54
 55// 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 nil
 59	}
 60	return &TxBuilder{fn: fn, realm_XXX: r}
 61}
 62
 63// 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 nil
 67	}
 68	if key == "" {
 69		return b
 70	}
 71
 72	// Special case: "." prefix is for reserved keywords.
 73	if strings.HasPrefix(key, ".") {
 74		panic("invalid key")
 75	}
 76
 77	b.args = append(b.args, key, value)
 78	return b
 79}
 80
 81// AddArgs adds multiple key-value pairs at once. Arguments should be provided
 82// as pairs: AddArgs("key1", "value1", "key2", "value2").
 83func (b *TxBuilder) AddArgs(args ...string) *TxBuilder {
 84	if b == nil {
 85		return nil
 86	}
 87	if len(args)%2 != 0 {
 88		panic("odd number of arguments")
 89	}
 90	// Add key-value pairs
 91	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 b
 97}
 98
 99// 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 nil
103	}
104	if amount == "" {
105		return b
106	}
107	b.send = amount
108	return b
109}
110
111// 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.args
117	if b.send != "" {
118		args = append(args, ".send", b.send)
119	}
120	return b.realm_XXX.Call(b.fn, args...)
121}
122
123// Call returns a URL for the specified function with optional key-value
124// arguments, for the current realm.
125func Call(fn string, args ...string) string {
126	return Realm("").Call(fn, args...)
127}
128
129// prefix returns the URL prefix for the realm.
130func (r Realm) prefix() string {
131	// relative
132	if r == "" {
133		curPath := unsafe.CurrentRealm().PkgPath()
134		return strings.TrimPrefix(curPath, chainDomain)
135	}
136
137	// local realm -> /realm
138	rlm := string(r)
139	if strings.HasPrefix(rlm, chainDomain) {
140		return strings.TrimPrefix(rlm, chainDomain)
141	}
142
143	// remote realm -> https://remote.land/realm
144	return "https://" + string(r)
145}
146
147// Call returns a URL for the specified function with optional key-value
148// arguments.
149func (r Realm) Call(fn string, args ...string) string {
150	if len(args) == 0 {
151		return r.prefix() + "$help&func=" + fn
152	}
153
154	// 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{}
157
158	// Check if args length is even
159	if len(args)%2 != 0 {
160		panic("odd number of arguments")
161	}
162	// Add key-value pairs to values
163	for i := 0; i < len(args); i += 2 {
164		key := args[i]
165		value := args[i+1]
166		values.Add(key, value)
167	}
168
169	// Build the base URL and append encoded query parameters
170	return r.prefix() + "$help&func=" + fn + "&" + values.Encode()
171}