package tron import ( "strings" "time" ) // Client is the subset of tronpy's Tron client used by kisstron. type Client struct { provider *HTTPProvider network string feeLimit int64 } // NewClient builds a client for the given network and node endpoint. A zero or // empty endpoint selects the network default. func NewClient(network, endpoint string, feeLimit int64, apiKey string) *Client { return &Client{ provider: NewHTTPProvider(endpoint, 20*time.Second, apiKey), network: network, feeLimit: feeLimit, } } // Provider exposes the underlying HTTP provider (used for diagnostics). func (c *Client) Provider() *HTTPProvider { return c.provider } func (c *Client) GetAccount(addr string) (map[string]any, error) { b58, err := ToBase58CheckAddress(addr) if err != nil { return nil, err } ret, err := c.provider.makeRequest("wallet/getaccount", map[string]any{"address": b58, "visible": true}) if err != nil { return nil, err } if len(ret) == 0 { return nil, ErrAddressNotFound } return ret, nil } func (c *Client) GetAccountResource(addr string) (map[string]any, error) { b58, err := ToBase58CheckAddress(addr) if err != nil { return nil, err } ret, err := c.provider.makeRequest("wallet/getaccountresource", map[string]any{"address": b58, "visible": true}) if err != nil { return nil, err } if len(ret) == 0 { return nil, ErrAddressNotFound } return ret, nil } func (c *Client) getLatestSolidBlockID() (string, error) { info, err := c.provider.makeRequest("wallet/getnodeinfo", nil) if err != nil { return "", err } block, _ := info["solidityBlock"].(string) if block == "" { return "", ErrAPI } return block[strings.LastIndex(block, ",ID:")+4:], nil } func (c *Client) broadcast(tx *Transaction) (map[string]any, error) { payload, err := c.provider.makeRequest("wallet/broadcasttransaction", tx) if err != nil { return nil, err } if err := handleAPIError(payload); err != nil { return nil, err } if _, ok := payload["txid"]; !ok { payload["txid"] = tx.TxID } return payload, nil } func (c *Client) getTransactionInfo(txid string) (map[string]any, error) { if len(txid) != 64 { return nil, ErrBadHash } ret, err := c.provider.makeRequest("wallet/gettransactioninfobyid", map[string]any{"value": txid, "visible": true}) if err != nil { return nil, err } if err := handleAPIError(ret); err != nil { return nil, err } if len(ret) == 0 { return nil, ErrTransactionNotFound } return ret, nil } func (c *Client) GetContract(addr string) (*Contract, error) { b58, err := ToBase58CheckAddress(addr) if err != nil { return nil, err } info, err := c.provider.makeRequest("wallet/getcontract", map[string]any{"value": b58, "visible": true}) if err != nil { return nil, err } if err := handleAPIError(info); err != nil { return nil, wrapErr(ErrContractNotFound, err.Error()) } return &Contract{Address: b58, client: c}, nil } // triggerConstantContract performs a read-only contract call and returns the // first constant result (hex, without 0x). func (c *Client) triggerConstantContract(owner, contractAddr, functionSelector, parameter string) (string, error) { ownerB58, err := ToBase58CheckAddress(owner) if err != nil { return "", err } contractB58, err := ToBase58CheckAddress(contractAddr) if err != nil { return "", err } ret, err := c.provider.makeRequest("wallet/triggerconstantcontract", map[string]any{ "owner_address": ownerB58, "contract_address": contractB58, "function_selector": functionSelector, "parameter": parameter, "visible": true, }) if err != nil { return "", err } if err := handleAPIError(ret); err != nil { return "", err } if res, ok := ret["result"].(map[string]any); ok { if _, bad := res["message"]; bad { return "", ErrTvm } } results, ok := ret["constant_result"].([]any) if !ok || len(results) == 0 { return "", ErrTvm } first, _ := results[0].(string) return first, nil }