diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index de27ba1..0ecc259 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -36,7 +36,7 @@ Cargo workspace: `bin/rwa` (entry point) → `crates/cli` (clap parsing, output) ``` rwa gm hours # Market status -rwa gm list # All 438 tokens +rwa gm list # All 450 tokens rwa gm buy --dry-run # Preview trade (no separate quote command) rwa gm buy/sell -y # Execute trade rwa gm close-all -y # Sell ALL positions (parallel by default; skips dust <$1.50 and temporarily unsellable positions) diff --git a/.github/workflows/update-token-list.yml b/.github/workflows/update-token-list.yml deleted file mode 100644 index 2b1a543..0000000 --- a/.github/workflows/update-token-list.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Update token list - -# Refresh the hardcoded Ondo GM token list (crates/ondo/src/token_list.rs) from -# the live Ondo asset universe + Jupiter mint resolution. Mints stay hardcoded; -# this only automates regenerating them. A human reviews and merges the PR — -# that review is the safety gate that catches any unexpected addition (e.g. a -# new non-equity Ondo product, or a symbol that fails mint-authority checks). - -on: - schedule: - - cron: "0 6 * * 1" # Mondays 06:00 UTC - workflow_dispatch: {} - -permissions: - contents: write - pull-requests: write - -jobs: - refresh: - name: Regenerate & open PR - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 - with: - python-version: "3.x" - - - name: Regenerate token_list.rs - run: python3 scripts/update-token-list.py - - - name: Detect changes - id: diff - run: | - if git diff --quiet -- crates/ondo/src/token_list.rs; then - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "Token list already up to date." - else - echo "changed=true" >> "$GITHUB_OUTPUT" - fi - - # Validate the regenerated list before proposing it: integrity tests - # (count, sort, uniqueness, base58→32 bytes, canary mints) must pass. - - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable - if: steps.diff.outputs.changed == 'true' - - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - if: steps.diff.outputs.changed == 'true' - - - name: Validate token list - if: steps.diff.outputs.changed == 'true' - run: cargo test -p rwa-ondo token_list - - - name: Open pull request - if: steps.diff.outputs.changed == 'true' - uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6 - with: - branch: chore/update-token-list - commit-message: "chore(tokens): refresh GM token list from Ondo + Jupiter" - title: "chore(tokens): refresh GM token list" - body: | - Automated refresh of `crates/ondo/src/token_list.rs`. - - Source of truth: - - Symbols: Ondo `/api/v2/assets` (tokenized equities/ETFs, suffix `on`) - - Mints: Jupiter token search, verified against Ondo's mint authority - - Gates that passed before this PR was opened (in `update-token-list.py`): - - **Form**: unique symbols/mints, base58 → 32 bytes, `on` suffix - - **On-chain**: every mint exists on Solana as a Token-2022 mint with - Ondo's issuer authority (`getMultipleAccounts`) - - **Tradability**: every symbol is in Ondo session-limits and tradable - in ≥1 session (the CLI's own tradability source — not a flaky live - Jupiter RFQ quote) - - **Integrity tests**: `cargo test -p rwa-ondo token_list` - - **Review the diff before merging** — confirm any added/removed symbols - are expected. The checks exclude look-alike tokens and non-Solana junk, - but a human gate catches new non-equity Ondo products and surprises. - labels: automated, tokens diff --git a/Cargo.lock b/Cargo.lock index 9204735..c539632 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,9 +633,9 @@ dependencies = [ [[package]] name = "chacha20" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", "cpufeatures 0.3.0", @@ -2781,7 +2781,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ - "chacha20 0.10.1", + "chacha20 0.10.2", "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -3072,9 +3072,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "once_cell", "ring", @@ -3096,9 +3096,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "ring", "rustls-pki-types", diff --git a/README.md b/README.md index 26e54e9..f38b00e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rwa — Trade Tokenized Stocks on Solana -CLI for buying & selling tokenized stocks and ETFs ([Ondo Global Markets](https://ondo.finance/)) on Solana via Jupiter. 438 tokens — TSLA, AAPL, NVDA, SPY, QQQ, and more. Flagship tokens trade 24/7. +CLI for buying & selling tokenized stocks and ETFs ([Ondo Global Markets](https://ondo.finance/)) on Solana via Jupiter. 450 tokens — TSLA, AAPL, NVDA, SPY, QQQ, and more. Flagship tokens trade 24/7. > **⚠️ Beta (pre-v1).** Breaking changes possible. Not financial advice — use at your own risk, and always preview with `--dry-run` before trading real funds. diff --git a/crates/ondo/src/token_list.rs b/crates/ondo/src/token_list.rs index 607b7c7..9d66a05 100644 --- a/crates/ondo/src/token_list.rs +++ b/crates/ondo/src/token_list.rs @@ -23,7 +23,7 @@ pub fn get_token_list() -> &'static [GmTokenEntry] { &TOKEN_LIST } -/// Static fallback list of Ondo GM tokens (439 tokens). +/// Static fallback list of Ondo GM tokens (450 tokens). /// Tuple: (symbol, solana_mint_address) static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("AALon", "9wYZetvT8J2ptfsRca5gzLBGvcUug38mp9yT3xaondo"), @@ -44,6 +44,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("AGon", "hrZ5vs6c6v1iWyvEXjGSHs3sQuuj58VzXikNyRWondo"), ("AIPon", "jmnrdSzu293vKTWyEx3A2ZRVxxytJKW1wD3CLzkondo"), ("AIQon", "uwh6Z6c2F8WZfUSK1A8VBfA9AwJKN5T2bvQwVFLondo"), + ("AIon", "rVMtUyy1ohurejV9qd81y9cPRHNA1A2QqWAErqfondo"), ("ALABon", "cskxd6aqyqJMYgLZmFYfYecWkjasRJDEtm1QVxsondo"), ("ALBon", "B5KufqHkskgGYwMXtL8FSHgREAkMQvE3ykhH5Kmondo"), ("ALOYon", "ndHvUEgrvZquSR6wZv2cG1AiBr7e7HGuWvfPULcondo"), @@ -194,6 +195,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("GMEon", "aznKt8v32CwYMEcTcB4bGTv8DXWStCpHrcCtyy7ondo"), ("GNRCon", "eqzwohR9oCR6sravF4y5HyUwyvCDbnfSYqiiFrXondo"), ("GOOGLon", "bbahNA5vT9WJeYft8tALrH1LXWffjwqVoUbqYa1ondo"), + ("GOOGon", "jcA9zXHWuTuDFDDDDYJTNhersed1B5etkuB6X9Eondo"), ("GRABon", "m9GcsVgdjaL3KsdtSFHimnhtsUMpTHkjtwEG4Tzondo"), ("GRNDon", "Gc1aT3ay7FXL3qdAW7cNSXYPDsGavy7qiACuxwxondo"), ("GSon", "BchJRy2snmhJZf3rQ9LJ3ePs2BGfYgfvQNo31d2ondo"), @@ -207,8 +209,11 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("HOODon", "BVdXGvmgi6A9oAiwWvBvP76fyTqcCNRJMM7zMN6ondo"), ("HPEon", "axbgKgUMscTJ34DjA69kBJuf6UYq4Pzb8B8numYondo"), ("HSAIon", "nagL8iWMNLZVuKFk3bUGDaHyT5ZY4bNfUzsdtGHondo"), + ("HTZon", "QApMAZTHvfhX2dTDzM8AMyAHVyhmPVwj4oY8Jveondo"), ("HUBBon", "ZmiDoowvkpp1Qgx4mmY3qtsHbNV1oE12ApKCbZNondo"), ("HUTon", "f7iz4BQsnjw95EUyFiBKAnKgo7oBrycfzQdtmDwondo"), + ("HYDBon", "71VH3YQkjqqGxzwYvGhsCsJNQYzkMo9Rg72aVxqondo"), + ("HYGWon", "ZKzkbFi4n3NQmRA9i5T7jVPSN2XERwxfHUf4p2pondo"), ("HYGon", "c5ug15fwZRfQhhVa6LHscFY33ebVDHcVCezYpj7ondo"), ("HYSon", "CsN1Tyz467bSFLPGd6MJyZhPNtwDaWZtX8ixHWyondo"), ("IALTon", "gfKuBLive7Q35MYgxPgNx7qx524zQJ9RiDZJFZoondo"), @@ -290,6 +295,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("MYRGon", "auLvQAhUzPuy2SQBSq2T6AofPGNkR4nZ83P8pjuondo"), ("NATon", "mmy8WbFRNrjoDsPGqpYmzQAVu7PfGhMCdSRLxZLondo"), ("NBISon", "DiRshqNDE68bWbGdLHm1GwQ76MvWQG3af6w1NdQondo"), + ("NEARon", "bD6TafGhPo8NaeKEyge1DrZGAPB5wxK3x4fCpqjondo"), ("NEEon", "t7eN6cGwRMFaZvsNW2SmVwkedmHtDdrxA4ycNE5ondo"), ("NEMon", "Dig28Tf1ufhCBAsjTmFkXCgcNgMqDMYj5A2rDQmondo"), ("NETon", "ZtAY65FCh3YB9H1wkbjRxxY5nXt9VfuTTz3Mzbuondo"), @@ -362,12 +368,14 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("RMBSon", "jjnSEAsi8UbCez7x9XCbWntLWRHBdc2tWSdC3uoondo"), ("ROKon", "e83tWWrVsVk1hRGNz5BCwNr9TMBNWixmoUhWgYcondo"), ("RTXon", "12BvLZtzjdssAycxPeBQUjukhmgQpULAvy6SroYdondo"), + ("RXRXon", "q16ZLSbANUhpcq15pRUXRxNFfEqgpde9mSBwRcyondo"), ("SAPon", "bjbrNi96mXAzgvxSuGJ2SRJ5U4N8agbG7wUAKAjondo"), ("SATAon", "vZVGEJfSM1hS4XdFVAZL2Fr1cbPzJty9vWyax68ondo"), ("SBETon", "iLDu2jjp2i3Uqc2Vm7K7GLiUj3hR4Un49MtD7c4ondo"), ("SBUXon", "iPFqjcZQTNMNXA4kbShbMhfAVD8yr8Uq9UtXMV6ondo"), ("SCCOon", "EANjzFjj3nPXHdzN5CE3Z8LLVn69Ce77FE8X4cvondo"), ("SCHWon", "cnc6M1zXLdrGR5LAQVcaJDfgezMiVWNtGQsVy1Kondo"), + ("SECUon", "sDtEN5uwUJJCFJ95x2rPjPqNx5UWUbHQ2ucceUzondo"), ("SEDGon", "EAwP9LGNjTkQ2YeKE6CGKqBYtrJ6APFvRe7KCMmondo"), ("SGOVon", "HjrN6ChZK2QRL6hMXayjGPLFvxhgjwKEy135VRjondo"), ("SHLDon", "siVse6kjZb9ihaXHaqoG3mhHyTPEnNCkvSDTheoondo"), @@ -401,6 +409,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("STXon", "EXtprP1wzrNo2bByrU9JyzqEg2hQMSCVJakeHHYondo"), ("SWKSon", "iJtKb1CWnWdgJhs7HgSZvLmSJABGGMc97QeuG7tondo"), ("SYMon", "nP42LxpSZkUfnBUxiFsHxL5GKYWRZ1VxqGkMTNwondo"), + ("SYSBon", "5U9o49BoQNU6bBMswvmBs3R4GZmYSyrnTN4ncX4ondo"), ("TASKon", "nQysX1ZsRJ8yTJg8smZTZ91rWcVBabDRqdUEKZHondo"), ("TCOMon", "9PMjLqd8zPdKkJUXarnit5t7tPL3cCscwHzy7ATondo"), ("TELon", "ZjYCwYeG85TbV5oXkCkvWQTNPh2PgTQ8X4nxpbyondo"), @@ -433,6 +442,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("URNMon", "hieZTEZNBU67bMGULK9hWCB9h5jBPKdpRWiXpwkondo"), ("USARon", "aA1dRckexLmQyppFoWmjKDFjrNFUsZeGzZ7L5xpondo"), ("USFRon", "o6U1Sm6Vd7EofMyCrL28mrp2QLzgYGgjveHiEQ5ondo"), + ("USHYon", "aau4XCAZR6p9uC4vgdHdh4ip3oW5pr5PrNs3FJ8ondo"), ("USOon", "rpydAzWdCy85HEmoQkH5PVxYtDYQWjmLxgHHadxondo"), ("UUUUon", "ey16y4Bk92zmPSvbRznuv3RioAXbVreBkQxrKGDondo"), ("VCXon", "esgtAV7yKf7Ei3Q92VmXcEGkoqY2UqCHzZvCWhgondo"), @@ -452,6 +462,7 @@ static GM_TOKENS_STATIC: &[(&str, &str)] = &[ ("Von", "kxEW4oJL75K37VeXaZF1ynbHQATQwhECQKN1374ondo"), ("WCCon", "m3m2HAANsAf2Y3BkdBixDgtrrFHnZDp4NqVh9obondo"), ("WDCon", "FLqH2jB2DZPJP5nnVFAakRKaNTcDZtq71Pnpp6Aondo"), + ("WENon", "QwJ619MuDRvT1f29RH7tMdaqsUnaSNcvBEJAZkHondo"), ("WFCon", "L6ZE5qCpVVSqLePz64CrwkgyWoPF9M7tB8BeFH4ondo"), ("WLKon", "mrNSd1y72F7Dx2Uip4vidtsJKKd8iJatTKGX6Pvondo"), ("WMBon", "bvjmEwQBqbMr6rnx5a74boBz6nmA1DNThujPnNAondo"), diff --git a/llms.txt b/llms.txt index 50aeca8..a423f6c 100644 --- a/llms.txt +++ b/llms.txt @@ -1,7 +1,7 @@ # rwa CLI CLI for trading tokenized stocks & ETFs (Ondo Global Markets) on Solana via Jupiter. -438 tokens: TSLA, AAPL, NVDA, SPY, QQQ, and more. +450 tokens: TSLA, AAPL, NVDA, SPY, QQQ, and more. ## Install diff --git a/scripts/__pycache__/update-token-list.cpython-314.pyc b/scripts/__pycache__/update-token-list.cpython-314.pyc new file mode 100644 index 0000000..c06bffa Binary files /dev/null and b/scripts/__pycache__/update-token-list.cpython-314.pyc differ diff --git a/scripts/update-token-list.py b/scripts/update-token-list.py index 0c1a957..e26449b 100755 --- a/scripts/update-token-list.py +++ b/scripts/update-token-list.py @@ -21,7 +21,7 @@ Modes: (default) rewrite token_list.rs in place --check exit 1 if the generated list differs from the committed file - (no write) — used by CI to detect drift + (no write) — run manually before a release Network failures on individual symbols are retried; a symbol that never resolves aborts the run (fail-closed) rather than silently dropping a token.