Skip to content

feat(bindings/go): add Go bindings#166

Open
okwn wants to merge 2 commits intoopen-wallet-standard:mainfrom
okwn:feat/go-binding
Open

feat(bindings/go): add Go bindings#166
okwn wants to merge 2 commits intoopen-wallet-standard:mainfrom
okwn:feat/go-binding

Conversation

@okwn
Copy link
Copy Markdown

@okwn okwn commented Apr 2, 2026

Summary

This PR adds Go bindings under bindings/go for the Open Wallet Standard.

The initial Go surface is intentionally small and focused:

  • wallet creation
  • wallet listing
  • message signing
  • transaction signing

The binding is implemented as a thin Go layer over a Rust FFI crate and includes Go tests, example usage, CI coverage, and platform-specific build notes for CGO on Windows.

What’s included

  • a new Go binding under bindings/go
  • Rust FFI support for the Go binding
  • Go API for:
    • CreateWallet
    • ListWallets
    • SignMessage
    • SignTx
  • uint32-aligned account index handling across the Go API and FFI contract
  • regression coverage for IndexNone
  • Go tests and example program
  • README instructions for local build/test flow
  • CI workflow coverage for the Go binding

Design notes

  • The public Go API is intentionally minimal for v1.
  • The FFI account-index contract is kept as uint32, including IndexNone.
  • The PR is scoped only to bindings/go/** and excludes unrelated simulation-first work.

Validation

Validated locally in the dedicated Go binding worktree with:

  • cargo test -p ows-go
  • cargo build --release -p ows-go
  • go build ./ows/...
  • go vet ./ows/...
  • go test -v ./ows/...
  • cargo build -p ows-node

Notes

The following issues are unrelated to this PR and were observed as pre-existing or environment-specific on this Windows machine:

  • cargo clippy --workspace -- -D warnings has an unrelated Windows dead_code failure in the base workspace
  • cargo test --workspace has unrelated Windows executable-policy test failures in ows-lib
  • cargo build -p ows-python is blocked locally by Python 3.14 vs PyO3 0.24.2 compatibility

Note

Medium Risk
Adds a new cross-language (Rust↔Go) FFI surface plus CGO linking and CI across Linux/Windows/macOS; ABI/memory-handling and platform loader differences are the main risk areas despite a small public API and test coverage.

Overview
Introduces a new bindings/go module that exposes a minimal Go API (CreateWallet, ListWallets, SignMessage, SignTx) backed by a Rust cdylib FFI layer returning JSON and a thread-local last-error code/message contract.

Adds comprehensive Go tests and a runnable demo, plus a dedicated GitHub Actions workflow to build the Rust library, run clippy, and execute Go fmt/vet/tests on Linux/Windows/macOS with the required CGO linker/runtime environment setup.

Written by Cursor Bugbot for commit 8476a12. This will update automatically on new commits. Configure here.

@okwn okwn requested a review from njdawn as a code owner April 2, 2026 19:39
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 2, 2026

@okwn is attempting to deploy a commit to the MoonPay Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgolang/​github.com/​stretchr/​testify@​v1.9.096100100100100

View full report

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

return nil
}
return &Error{Code: code, Message: C.GoString(C.ows_go_get_last_error())}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thread-local error state breaks with Go goroutine scheduling

High Severity

The lastError() function reads Rust thread-local error state across multiple separate CGO calls (ows_go_get_last_error_code then ows_go_get_last_error). Go goroutines can migrate between OS threads between any two CGO calls, so after an FFI function sets an error on thread A, the goroutine may be rescheduled to thread B before lastError() runs. This can cause silent error swallowing (returning nil, nil), mismatched error codes/messages, or a segfault if C.GoString receives a NULL pointer from a thread with no error set. No runtime.LockOSThread call is present anywhere in the package.

Additional Locations (1)
Fix in Cursor Fix in Web

write!(&mut json, r#""created_at":"{}""#, info.created_at).unwrap();
json.push('}');
json
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manual JSON serialization lacks character escaping

Medium Severity

wallet_info_to_json uses Rust's write! with {} format specifier to interpolate user-controlled strings (wallet name, addresses, etc.) directly into JSON. This does not escape JSON special characters like ", \, or control characters. A wallet name containing a double quote produces malformed JSON that fails to parse on the Go side, causing the operation to return a misleading parse error even though the wallet was successfully created.

Additional Locations (1)
Fix in Cursor Fix in Web

unsafe { CStr::from_ptr(s) }.to_str().unwrap_or(""),
))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty vault path string bypasses default path resolution

Medium Severity

The Go API documents that passing "" for vaultPath uses the default vault (~/.ows), but opt_path only maps NULL pointers to None — a Go empty string becomes C.CString(""), a non-null pointer, which produces Some(Path::new("")) in Rust. The underlying resolve_vault_path treats Some("") as an explicit (empty) path rather than None, so wallets get created relative to the working directory instead of the documented default location.

Additional Locations (1)
Fix in Cursor Fix in Web

@njdawn
Copy link
Copy Markdown
Contributor

njdawn commented Apr 3, 2026

could you resolve or fix or push-back on cursor bug-bot comments before requesting review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants