{"id":20272307,"url":"https://github.com/steemit/steemutil","last_synced_at":"2026-01-24T00:04:40.535Z","repository":{"id":72308942,"uuid":"599206526","full_name":"steemit/steemutil","owner":"steemit","description":"Provides steem-specific convenience functions and types for go","archived":false,"fork":false,"pushed_at":"2025-12-17T17:44:00.000Z","size":89,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-21T06:04:20.399Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steemit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-02-08T17:10:43.000Z","updated_at":"2025-12-17T17:42:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"1f5e7853-19b2-4873-9b67-c6b31a14f15a","html_url":"https://github.com/steemit/steemutil","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/steemit/steemutil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Fsteemutil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Fsteemutil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Fsteemutil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Fsteemutil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steemit","download_url":"https://codeload.github.com/steemit/steemutil/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steemit%2Fsteemutil/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28017192,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-25T02:00:05.988Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T12:42:48.003Z","updated_at":"2025-12-25T02:12:55.244Z","avatar_url":"https://github.com/steemit.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# steemutil\n\n\u003e This is underconstruction. The methods will be change in the future !!!!\n\nPackage steemutil provides Steem blockchain-specific convenience functions and types for Go applications.\n\n## Overview\n\nsteemutil is a comprehensive Go library that provides low-level utilities for interacting with the Steem blockchain. It includes cryptographic functions, transaction handling, protocol definitions, and RPC authentication capabilities.\n\n## Features\n\n- **🔐 RPC Authentication**: SignedCall support for authenticated API requests\n- **🔑 Cryptographic Operations**: Key generation, signing, and verification\n- **📦 Transaction Handling**: Transaction creation, signing, and serialization\n- **🌐 Protocol Support**: Complete Steem protocol operation definitions\n- **🛡️ Security**: Built-in replay protection and signature validation\n- **⚡ Performance**: Optimized for high-performance applications\n\n## Installation\n\n```bash\ngo get github.com/steemit/steemutil\n```\n\n## Quick Start\n\n### Basic Key Operations\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/steemit/steemutil/auth\"\n)\n\nfunc main() {\n    // Generate private key from account and password\n    privateKey, err := auth.ToWif(\"username\", \"password\", \"active\")\n    if err != nil {\n        panic(err)\n    }\n    \n    // Convert to public key\n    publicKey, err := auth.WifToPublic(privateKey)\n    if err != nil {\n        panic(err)\n    }\n    \n    fmt.Printf(\"Private Key: %s\\n\", privateKey)\n    fmt.Printf(\"Public Key: %s\\n\", publicKey)\n}\n```\n\n### SignedCall RPC Authentication\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/steemit/steemutil/rpc\"\n)\n\nfunc main() {\n    // Create RPC request\n    request := \u0026rpc.RpcRequest{\n        Method: \"condenser_api.get_accounts\",\n        Params: []interface{}{[]string{\"username\"}},\n        ID:     1,\n    }\n    \n    // Sign the request\n    signedRequest, err := rpc.Sign(request, \"username\", []string{\"private-key-wif\"})\n    if err != nil {\n        panic(err)\n    }\n    \n    fmt.Printf(\"Signed Request: %+v\\n\", signedRequest)\n}\n```\n\n### Transaction Operations\n\n```go\npackage main\n\nimport (\n    \"github.com/steemit/steemutil/protocol\"\n    \"github.com/steemit/steemutil/transaction\"\n)\n\nfunc main() {\n    // Create a vote operation\n    voteOp := \u0026protocol.VoteOperation{\n        Voter:    \"voter\",\n        Author:   \"author\", \n        Permlink: \"permlink\",\n        Weight:   10000,\n    }\n    \n    // Create transaction\n    tx := \u0026transaction.Transaction{}\n    tx.PushOperation(voteOp)\n    \n    // Sign transaction\n    signedTx := transaction.NewSignedTransaction(tx)\n    // ... add signing logic\n}\n```\n\n## Package Structure\n\n### Core Packages\n\n- **`auth/`** - Authentication and key management utilities\n- **`rpc/`** - RPC authentication and signed call support  \n- **`protocol/`** - Steem protocol definitions and operations\n- **`transaction/`** - Transaction creation and signing\n- **`wif/`** - Wallet Import Format key handling\n- **`encoder/`** - Binary serialization utilities\n\n### Protocol Support\n\n- **`protocol/api/`** - API method definitions\n- **`protocol/broadcast/`** - Broadcast operation definitions\n- **`consts/`** - Protocol constants and chain parameters\n- **`jsonrpc2/`** - JSON-RPC client implementation\n\n## RPC Authentication (SignedCall)\n\nThe `rpc` package provides full support for Steem's signed RPC calls, compatible with steem-js:\n\n### Features\n\n- **🔒 Cryptographic Signing**: ECDSA signature generation and verification\n- **🛡️ Security**: Nonce generation, timestamp expiration (60s), replay protection\n- **🔄 Compatibility**: 100% compatible with steem-js signedCall format\n- **🔑 Multi-Key Support**: Sign with multiple private keys simultaneously\n- **⏰ Time Validation**: Automatic signature expiration handling\n\n### Security Features\n\n- **Unique Nonces**: 8-byte random nonce for each request\n- **Timestamp Expiration**: Signatures expire after 60 seconds\n- **Cross-Protocol Protection**: Protocol-specific signing constant K\n- **No Key Transmission**: Private keys never leave your application\n\n### Example Usage\n\n```go\n// Sign a request\nrequest := \u0026rpc.RpcRequest{\n    Method: \"condenser_api.get_account_history\",\n    Params: []interface{}{\"username\", -1, 100},\n    ID:     1,\n}\n\nsignedRequest, err := rpc.Sign(request, \"username\", []string{\"active-key-wif\"})\nif err != nil {\n    return err\n}\n\n// Validate a signed request\nparams, err := rpc.Validate(signedRequest, rpc.DefaultVerifyFunc)\nif err != nil {\n    return err\n}\n```\n\n## Cryptographic Operations\n\n### Key Generation\n\n```go\n// Generate keys for multiple roles\nroles := []string{\"active\", \"posting\", \"owner\", \"memo\"}\nkeys, err := auth.GetPrivateKeys(\"username\", \"password\", roles)\n\n// Generate single key\nactiveKey, err := auth.ToWif(\"username\", \"password\", \"active\")\n```\n\n### Message Signing\n\n```go\n// Sign arbitrary messages\nprivateKey := \u0026wif.PrivateKey{}\nprivateKey.FromWif(\"private-key-wif\")\n\nmessage := []byte(\"Hello, Steem!\")\nsignature, err := privateKey.SignSha256(message)\n\n// Verify signatures\npublicKey := \u0026wif.PublicKey{}\npublicKey.FromWif(\"private-key-wif\") // Derives public key\nisValid := publicKey.VerifySha256(message, signature)\n```\n\n## Transaction Handling\n\n### Creating Transactions\n\n```go\n// Create operations\nvoteOp := \u0026protocol.VoteOperation{\n    Voter:    \"voter\",\n    Author:   \"author\",\n    Permlink: \"post-permlink\", \n    Weight:   10000,\n}\n\ntransferOp := \u0026protocol.TransferOperation{\n    From:   \"sender\",\n    To:     \"receiver\",\n    Amount: \"1.000 STEEM\",\n    Memo:   \"Transfer memo\",\n}\n\n// Build transaction\ntx := \u0026transaction.Transaction{}\ntx.PushOperation(voteOp)\ntx.PushOperation(transferOp)\n\n// Sign transaction\nsignedTx := transaction.NewSignedTransaction(tx)\nerr := signedTx.Sign(privateKeys, transaction.SteemChain)\n```\n\n### Supported Operations\n\nThe library supports all Steem protocol operations:\n\n- **Content**: `comment`, `vote`, `delete_comment`\n- **Financial**: `transfer`, `transfer_to_savings`, `claim_reward_balance`\n- **Account**: `account_create`, `account_update`, `recover_account`\n- **Witness**: `witness_update`, `account_witness_vote`\n- **Market**: `limit_order_create`, `limit_order_cancel`\n- **Custom**: `custom_json`, `custom_binary`\n- **And many more...**\n\n### Working with Operation Data\n\nThe `Operation` interface provides a `Data() any` method that returns the operation data. Understanding how to use this method is important for type-safe operation handling.\n\n#### Return Types\n\nThe `Data()` method returns different types depending on the operation:\n\n- **Known Operations**: Returns the operation struct itself (e.g., `*VoteOperation`, `*TransferOperation`)\n- **Unknown Operations**: Returns `*json.RawMessage` for operations not recognized by the package\n\n#### Best Practices\n\n**1. Type Assertion Based on Operation Type**\n\nAlways check the operation type before performing type assertions:\n\n```go\nimport (\n    \"encoding/json\"\n    \"github.com/steemit/steemutil/protocol\"\n)\n\nfunc processOperation(op protocol.Operation) {\n    switch op.Type() {\n    case protocol.TypeVote:\n        // Type assertion is safe after checking Type()\n        voteOp := op.Data().(*protocol.VoteOperation)\n        fmt.Printf(\"Voter: %s, Author: %s\\n\", voteOp.Voter, voteOp.Author)\n        \n    case protocol.TypeTransfer:\n        transferOp := op.Data().(*protocol.TransferOperation)\n        fmt.Printf(\"From: %s, To: %s, Amount: %s\\n\", \n            transferOp.From, transferOp.To, transferOp.Amount)\n        \n    case protocol.TypeComment:\n        commentOp := op.Data().(*protocol.CommentOperation)\n        fmt.Printf(\"Author: %s, Title: %s\\n\", commentOp.Author, commentOp.Title)\n        \n    default:\n        // Handle unknown operations\n        if rawJSON, ok := op.Data().(*json.RawMessage); ok {\n            fmt.Printf(\"Unknown operation type: %s\\n\", op.Type())\n            fmt.Printf(\"Raw JSON: %s\\n\", string(*rawJSON))\n        }\n    }\n}\n```\n\n**2. Safe Type Assertion with Error Handling**\n\nUse type assertions with the two-value form for safer code:\n\n```go\nfunc safeProcessVote(op protocol.Operation) error {\n    if op.Type() != protocol.TypeVote {\n        return fmt.Errorf(\"expected vote operation, got %s\", op.Type())\n    }\n    \n    voteOp, ok := op.Data().(*protocol.VoteOperation)\n    if !ok {\n        return fmt.Errorf(\"failed to assert vote operation data\")\n    }\n    \n    // Use voteOp safely\n    fmt.Printf(\"Processing vote: %s -\u003e %s/%s\\n\", \n        voteOp.Voter, voteOp.Author, voteOp.Permlink)\n    return nil\n}\n```\n\n**3. Handling Unknown Operations**\n\nFor operations not recognized by the package, `Data()` returns `*json.RawMessage`:\n\n```go\nfunc handleUnknownOperation(op protocol.Operation) {\n    if rawJSON, ok := op.Data().(*json.RawMessage); ok {\n        // This is an unknown operation type\n        var data map[string]any\n        if err := json.Unmarshal(*rawJSON, \u0026data); err == nil {\n            fmt.Printf(\"Unknown operation data: %+v\\n\", data)\n        }\n    } else {\n        // This is a known operation type\n        fmt.Printf(\"Known operation: %s\\n\", op.Type())\n    }\n}\n```\n\n**4. Direct Operation Access**\n\nFor known operations, you can directly use the operation struct without calling `Data()`:\n\n```go\n// Instead of:\ndata := op.Data().(*protocol.VoteOperation)\n\n// You can directly cast the operation:\nif voteOp, ok := op.(*protocol.VoteOperation); ok {\n    // Use voteOp directly\n    fmt.Printf(\"Voter: %s\\n\", voteOp.Voter)\n}\n```\n\n**5. Iterating Over Operations**\n\nWhen processing multiple operations:\n\n```go\nfunc processOperations(ops protocol.Operations) {\n    for _, op := range ops {\n        switch op.Type() {\n        case protocol.TypeVote:\n            voteOp := op.Data().(*protocol.VoteOperation)\n            processVote(voteOp)\n            \n        case protocol.TypeTransfer:\n            transferOp := op.Data().(*protocol.TransferOperation)\n            processTransfer(transferOp)\n            \n        default:\n            // Log or handle unknown operations\n            fmt.Printf(\"Unhandled operation type: %s\\n\", op.Type())\n        }\n    }\n}\n```\n\n#### Important Notes\n\n- **Type Safety**: Always check `op.Type()` before performing type assertions\n- **Unknown Operations**: Use `*json.RawMessage` type assertion to handle unrecognized operations\n- **Performance**: Direct operation casting (e.g., `op.(*VoteOperation)`) is more efficient than using `Data()` for known types\n- **Compatibility**: The `any` return type allows the library to handle both known and unknown operation types flexibly\n\n## Testing\n\nRun the test suite:\n\n```bash\n# Run all tests\ngo test ./...\n\n# Run specific package tests\ngo test ./rpc -v\ngo test ./auth -v\ngo test ./protocol -v\n\n# Run with coverage\ngo test ./... -cover\n```\n\n## Examples\n\nSee the [examples directory](../test-gosdk/examples/) for complete working examples:\n\n- **SignedCall Authentication**: `examples/signed_call/`\n- **Key Generation**: `examples/generate_keys/`\n- **Transaction Broadcasting**: `examples/transfer/`\n- **Vote Operations**: `examples/vote_post/`\n\n## API Reference\n\n### Authentication (`auth/`)\n\n- `ToWif(name, password, role string) (string, error)` - Generate WIF from credentials\n- `GetPrivateKeys(name, password string, roles []string) (map[string]string, error)` - Generate multiple keys\n- `WifToPublic(wif string) (string, error)` - Convert WIF to public key\n- `IsWif(wif string) bool` - Validate WIF format\n- `Verify(name, password string, auths map[string]interface{}) (bool, error)` - Verify credentials\n\n### RPC Authentication (`rpc/`)\n\n- `Sign(request *RpcRequest, account string, keys []string) (*SignedRequest, error)` - Sign RPC request\n- `Validate(request *SignedRequest, verifyFunc func(...) error) ([]interface{}, error)` - Validate signed request\n- `SignRequest(method string, params []interface{}, id int, account, key string) (*SignedRequest, error)` - Convenience function\n\n### Transaction (`transaction/`)\n\n- `NewSignedTransaction(tx *Transaction) *SignedTransaction` - Create signed transaction\n- `(tx *SignedTransaction) Sign(keys []*wif.PrivateKey, chain *Chain) error` - Sign transaction\n- `(tx *SignedTransaction) Digest(chain *Chain) ([]byte, error)` - Calculate transaction digest\n- `(tx *SignedTransaction) Serialize() ([]byte, error)` - Serialize transaction\n\n### WIF Operations (`wif/`)\n\n- `(pk *PrivateKey) FromWif(wif string) error` - Import from WIF\n- `(pk *PrivateKey) ToWif() string` - Export to WIF\n- `(pk *PrivateKey) SignSha256(message []byte) ([]byte, error)` - Sign message\n- `(pk *PublicKey) VerifySha256(message, signature []byte) bool` - Verify signature\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Related Projects\n\n- **[steemgosdk](https://github.com/steemit/steemgosdk/)** - High-level Steem Go SDK built on steemutil\n- **[steem-js](https://github.com/steemit/steem-js)** - JavaScript Steem library (compatible with our SignedCall)\n- **[steem](https://github.com/steemit/steem)** - Official Steem blockchain implementation\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/steemit/steemutil/issues)\n- **Documentation**: [API Documentation](https://pkg.go.dev/github.com/steemit/steemutil)\n\n---\n\n**Note**: This library provides low-level utilities. For high-level application development, consider using [steemgosdk](https://github.com/steemit/steemgosdk/) which provides a more convenient API built on top of steemutil.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteemit%2Fsteemutil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteemit%2Fsteemutil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteemit%2Fsteemutil/lists"}