{"id":23532611,"url":"https://github.com/conduition/wos","last_synced_at":"2025-04-22T22:41:00.895Z","repository":{"id":221467019,"uuid":"754430634","full_name":"conduition/wos","owner":"conduition","description":"API client for the \"Wallet of Satoshi\" Bitcoin Lightning app.","archived":false,"fork":false,"pushed_at":"2024-10-03T17:48:21.000Z","size":32,"stargazers_count":7,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T19:34:31.735Z","etag":null,"topics":["bitcoin","lightning-network","lsp-client","rest-api","web-wallet"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/conduition.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}},"created_at":"2024-02-08T03:05:05.000Z","updated_at":"2025-03-03T22:22:07.000Z","dependencies_parsed_at":"2024-02-08T06:24:07.116Z","dependency_job_id":"8b080102-219b-468b-a043-0658af0ffb6f","html_url":"https://github.com/conduition/wos","commit_stats":null,"previous_names":["conduition/wos"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conduition%2Fwos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conduition%2Fwos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conduition%2Fwos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conduition%2Fwos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/conduition","download_url":"https://codeload.github.com/conduition/wos/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250337208,"owners_count":21414085,"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","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":["bitcoin","lightning-network","lsp-client","rest-api","web-wallet"],"created_at":"2024-12-25T23:11:54.634Z","updated_at":"2025-04-22T22:41:00.876Z","avatar_url":"https://github.com/conduition.png","language":"Go","readme":"# `wos`\n\nAPI client for the Wallet of Satoshi Bitcoin Lightning app.\n\n[Wallet of Satoshi](https://walletofsatoshi.com/) is a custodial Bitcoin Lightning wallet app. It is effectively a [web-wallet](https://www.whatisbitcoin.com/learn/what-is-a-web-wallet), because the signing keys are actually hosted on WoS servers, while their mobile app is just a thin API client around their backend sevice.\n\nBy using WoS, Bitcoiners trade security for ease-of-use. WoS is well known for being a very beginner-friendly Lightning wallet, due largely to this trade-off. WoS can run off with your money, but you also don't have to worry about running a node, managing channels, updating software, and so forth.\n\nSince WoS is a no-KYC no-signup-required web-wallet, it is very easy to reverse-engineer their API for programmatic use. New wallets can be created on-the-fly with no API credentials needed. Existing wallets can be accessed using simple API credentials.\n\nThis library is a Golang package which encapsulates the WoS v1 REST API.\n\n## Usage\n\nThe `Wallet` struct type provides a full interface to the WoS API, including creating invoices and sending payments both on-chain and over Lightning.\n\n```golang\npackage main\n\nimport (\n  \"context\"\n  \"fmt\"\n  \"os\"\n\n  \"github.com/conduition/wos\"\n)\n\nfunc main() {\n  ctx := context.Background()\n\n  // First, create a wallet from scratch. It will have empty balances\n  // but you can start depositing right away via lightning.\n  wallet, creds, err := wos.CreateWallet(ctx, nil)\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(wallet.LightningAddress())\n\n  // The Credentials should be saved somewhere, so that you can\n  // regain access to the same wallet later.\n  os.WriteFile(\n    \"/secure/location/wos-creds\",\n    []byte(creds.APIToken+\"\\n\"+creds.APISecret),\n    0o600,\n  )\n\n  // To reopen the wallet after going offline, parse the Credentials\n  // from the disk, and then use Credentials.OpenWallet.\n  wallet, err = creds.OpenWallet(ctx, nil)\n  if err != nil {\n    panic(err)\n  }\n\n  // Create an invoice.\n  invoice, err := wallet.NewInvoice(ctx, \u0026wos.InvoiceOptions{\n    Amount:      0.0001,\n    Description: \"don't actually send money to this invoice.\",\n  })\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(invoice.Bolt11)\n\n  // Pay an invoice.\n  payment, err := wallet.PayInvoice(ctx, invoice.Bolt11, \"a payment label, can be omitted\")\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(payment.Status, payment.Amount, payment.Currency, payment.Time)\n}\n```\n\n## Segregated Credentials\n\nWoS credentials are split into a bearer _API token_ and a shared _API secret._\n\nThe token is passed as a header with every HTTP request to the WoS API, while the secret is used to produce HMACs for POST requests.\n\nThe secret-signature is only required for POST requests which change wallet state - such as creating or paying invoices, GET requests - such as fetching balance or payment history - require only the _API token._ This means a WoS API client can be segregated into a `Reader` and a `Signer`.\n\nA `Reader` can view a WoS account's balances and ongoing payments in real-time, while A `Signer` is an interface type which can be a simple wrapper around the API Secret, or the API secret could live offline or on a more secure machine which validates \u0026 signs POST requests, enforcing arbitrary user-defined rules (e.g. only allow max $50 per purchase, or max $1000 per day, etc). Put both together and you get a `Wallet`.\n\nThe `wos` package fully supports this kind of architecture. For example, consider this example with a `Signer` which lives on a remote machine. Signatures are fetched via HTTP POST requests.\n\n```golang\npackage main\n\nimport (\n  \"bytes\"\n  \"context\"\n  \"encoding/json\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n\n  \"github.com/conduition/wos\"\n)\n\ntype RemoteSigner struct {\n  URL string\n}\n\nfunc (rs RemoteSigner) SignRequest(\n  ctx context.Context,\n  endpoint, nonce, requestBody, apiToken string,\n) ([]byte, error) {\n  bodyBytes, err := json.Marshal(map[string]string{\n    \"endpoint\": endpoint,\n    \"nonce\":    nonce,\n    \"body\":     requestBody,\n  })\n  if err != nil {\n    return nil, err\n  }\n\n  req, err := http.NewRequestWithContext(ctx, \"POST\", rs.URL, bytes.NewReader(bodyBytes))\n  if err != nil {\n    return nil, err\n  }\n  req.Header.Set(\"Content-Type\", \"application/json\")\n\n  resp, err := http.DefaultClient.Do(req)\n  if err != nil {\n    return nil, err\n  }\n  defer resp.Body.Close()\n\n  if resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"received status code %d from remote signer\", resp.StatusCode)\n  }\n\n  return io.ReadAll(resp.Body)\n}\n\nfunc main() {\n  reader := wos.NewReader(\"93b9c574-30a2-4bf5-81ba-f9feadb313a7\", nil)\n  signer := RemoteSigner{\"https://somewheresecure.place/api/sign\"}\n  wallet, err := wos.OpenWallet(context.Background(), reader, signer)\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(wallet.LightningAddress())\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconduition%2Fwos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconduition%2Fwos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconduition%2Fwos/lists"}