├── .gitattributes ├── .github └── workflows │ └── publish.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── capi ├── main.go ├── parser.go ├── parser.h └── parser_test.go ├── go.mod ├── go.sum ├── main.go └── python ├── README.md ├── pdm.lock ├── pyproject.toml ├── src └── solana_tx_parser │ ├── __init__.py │ └── parser.py └── tests ├── examples └── raydium_pool_v4_swap_2.json └── test_parser.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.so filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build-libs: 10 | strategy: 11 | matrix: 12 | include: 13 | - os: ubuntu-latest 14 | artifact: libsoltxparser.so 15 | platform: linux 16 | - os: macos-latest 17 | artifact: libsoltxparser.dylib 18 | platform: macos 19 | - os: windows-latest 20 | artifact: soltxparser.dll 21 | platform: windows 22 | runs-on: ${{ matrix.os }} 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | lfs: true 27 | 28 | - name: Set up Go 29 | uses: actions/setup-go@v4 30 | with: 31 | go-version: '1.20' 32 | 33 | - name: Build library 34 | shell: bash 35 | run: | 36 | mkdir -p build 37 | if [ "${{ matrix.platform }}" = "windows" ]; then 38 | CGO_ENABLED=1 GOOS=windows go build -buildmode=c-shared -o build/soltxparser.dll ./capi 39 | mkdir -p python/src/solana_tx_parser/lib/ 40 | cp build/soltxparser.dll python/src/solana_tx_parser/lib/ 41 | else 42 | make 43 | fi 44 | 45 | - name: Upload library artifact 46 | uses: actions/upload-artifact@v3 47 | with: 48 | name: lib-${{ matrix.platform }} 49 | path: build/${{ matrix.artifact }} 50 | 51 | test-deploy: 52 | needs: build-libs 53 | runs-on: ubuntu-latest 54 | environment: testpypi 55 | steps: 56 | - uses: actions/checkout@v4 57 | with: 58 | lfs: true 59 | 60 | - name: Set up Python 61 | uses: actions/setup-python@v4 62 | with: 63 | python-version: '3.12' 64 | 65 | - name: Download all artifacts 66 | uses: actions/download-artifact@v3 67 | with: 68 | path: artifacts 69 | 70 | - name: Prepare libraries 71 | run: | 72 | mkdir -p python/src/solana_tx_parser/lib 73 | cp artifacts/lib-linux/libsoltxparser.so python/src/solana_tx_parser/lib/ 74 | cp artifacts/lib-macos/libsoltxparser.dylib python/src/solana_tx_parser/lib/ 75 | cp artifacts/lib-windows/soltxparser.dll python/src/solana_tx_parser/lib/ 76 | 77 | - name: Install PDM 78 | run: | 79 | curl -sSL https://pdm.fming.dev/install-pdm.py | python3 - 80 | 81 | - name: Build and publish to TestPyPI 82 | env: 83 | TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} 84 | run: | 85 | cd python 86 | VERSION=$(python3 -c "import time; print('0.0.1.dev' + time.strftime('%Y%m%d%H%M%S'))") 87 | sed -i "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml 88 | pdm build 89 | pdm publish --repository https://test.pypi.org/legacy/ --username __token__ --password $TEST_PYPI_API_TOKEN 90 | 91 | deploy: 92 | needs: [build-libs, test-deploy] 93 | if: github.event_name == 'release' 94 | runs-on: ubuntu-latest 95 | environment: release 96 | steps: 97 | - uses: actions/checkout@v4 98 | with: 99 | lfs: true 100 | 101 | - name: Set up Python 102 | uses: actions/setup-python@v4 103 | with: 104 | python-version: '3.12' 105 | 106 | - name: Download all artifacts 107 | uses: actions/download-artifact@v3 108 | with: 109 | path: artifacts 110 | 111 | - name: Prepare libraries 112 | run: | 113 | mkdir -p python/src/solana_tx_parser/lib 114 | cp artifacts/lib-linux/libsoltxparser.so python/src/solana_tx_parser/lib/ 115 | cp artifacts/lib-macos/libsoltxparser.dylib python/src/solana_tx_parser/lib/ 116 | cp artifacts/lib-windows/soltxparser.dll python/src/solana_tx_parser/lib/ 117 | 118 | - name: Install PDM 119 | run: | 120 | curl -sSL https://pdm.fming.dev/install-pdm.py | python3 - 121 | 122 | - name: Build and publish to PyPI 123 | env: 124 | PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} 125 | run: | 126 | cd python 127 | pdm build 128 | pdm publish --username __token__ --password $PYPI_API_TOKEN -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | .Python 6 | develop-eggs/ 7 | dist/ 8 | downloads/ 9 | eggs/ 10 | .eggs/ 11 | lib64/ 12 | parts/ 13 | sdist/ 14 | var/ 15 | wheels/ 16 | *.egg-info/ 17 | .installed.cfg 18 | *.egg 19 | 20 | # PDM 21 | .pdm-python 22 | .pdm.toml 23 | __pypackages__/ 24 | .venv/ 25 | 26 | # IDE 27 | .idea/ 28 | .vscode/ 29 | *.swp 30 | *.swo 31 | 32 | # Environment 33 | .env 34 | .venv 35 | env/ 36 | venv/ 37 | ENV/ 38 | 39 | # Testing 40 | .coverage 41 | .pytest_cache/ 42 | htmlcov/ 43 | 44 | # Distribution 45 | dist/ 46 | build/ 47 | *.egg-info/ 48 | .DS_Store 49 | lib/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | GOCMD=go 4 | GOBUILD=$(GOCMD) build 5 | GOCLEAN=$(GOCMD) clean 6 | BUILD_DIR=build 7 | 8 | # 检测操作系统 9 | UNAME_S := $(shell uname -s) 10 | ifeq ($(UNAME_S),Darwin) 11 | OUTPUT=libsoltxparser.dylib 12 | else ifeq ($(UNAME_S),Linux) 13 | OUTPUT=libsoltxparser.so 14 | else ifeq ($(OS),Windows_NT) 15 | OUTPUT=soltxparser.dll 16 | else 17 | $(error Unsupported operating system) 18 | endif 19 | 20 | all: $(BUILD_DIR)/$(OUTPUT) 21 | 22 | clean: 23 | $(GOCLEAN) 24 | rm -rf $(BUILD_DIR) 25 | 26 | $(BUILD_DIR): 27 | mkdir -p $(BUILD_DIR) 28 | 29 | $(BUILD_DIR)/$(OUTPUT): $(BUILD_DIR) 30 | CGO_ENABLED=1 $(GOBUILD) -buildmode=c-shared -o $@ ./capi 31 | mkdir -p python/src/solana_tx_parser/lib/ 32 | cp $(BUILD_DIR)/$(OUTPUT) python/src/solana_tx_parser/lib/ 33 | cp $(BUILD_DIR)/*.h python/src/solana_tx_parser/lib/ 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sol-tx-parser-capi 2 | 3 | A C API wrapper for [tx-parser](https://github.com/0xjeffro/tx-parser) with Python bindings. 4 | 5 | ## Usage 6 | 7 | See [python/README.md](python/README.md) for usage with Python. 8 | 9 | ## Build 10 | 11 | ```bash 12 | make 13 | cat build 14 | ``` 15 | 16 | ## Thanks 17 | 18 | - [tx-parser](https://github.com/0xjeffro/tx-parser) 19 | 20 | ## License 21 | 22 | See [LICENSE](LICENSE). 23 | -------------------------------------------------------------------------------- /capi/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This file is required for building a C shared library 4 | func main() {} 5 | -------------------------------------------------------------------------------- /capi/parser.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | char* error; 9 | char* result; 10 | } ParseResult; 11 | */ 12 | import "C" 13 | import ( 14 | "encoding/json" 15 | "unsafe" 16 | 17 | "github.com/0xjeffro/tx-parser/solana" 18 | "github.com/0xjeffro/tx-parser/solana/types" 19 | ) 20 | 21 | func _parseTransaction(txData string) (string, error) { 22 | var result types.RPCResponse 23 | 24 | err := json.Unmarshal([]byte(txData), &result) 25 | if err != nil { 26 | return "", err 27 | } 28 | 29 | var txs []types.RawTx 30 | txs = append(txs, result.Result) 31 | b, err := json.Marshal(txs) 32 | 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | parsed, err := solana.Parser(b) 38 | 39 | if err != nil { 40 | return "", err 41 | } 42 | 43 | parsedJson, err := json.Marshal(parsed) 44 | 45 | if err != nil { 46 | return "", err 47 | } 48 | 49 | return string(parsedJson), nil 50 | } 51 | 52 | //export ParseTransaction 53 | func ParseTransaction(txData *C.char) C.ParseResult { 54 | parsedJson, err := _parseTransaction(C.GoString(txData)) 55 | if err != nil { 56 | return C.ParseResult{ 57 | error: C.CString(err.Error()), 58 | result: nil, 59 | } 60 | } 61 | return C.ParseResult{ 62 | error: nil, 63 | result: C.CString(parsedJson), 64 | } 65 | } 66 | 67 | //export FreeParseResult 68 | func FreeParseResult(result C.ParseResult) { 69 | if result.error != nil { 70 | C.free(unsafe.Pointer(result.error)) 71 | } 72 | if result.result != nil { 73 | C.free(unsafe.Pointer(result.result)) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /capi/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef SOLANA_TX_PARSER_H 2 | #define SOLANA_TX_PARSER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef struct { 9 | char* error; 10 | char* result; 11 | } ParseResult; 12 | 13 | ParseResult ParseTransaction(const char* txData); 14 | void FreeParseResult(ParseResult result); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif // SOLANA_TX_PARSER_H 21 | -------------------------------------------------------------------------------- /capi/parser_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestParseTransaction(t *testing.T) { 9 | // Sample Solana transaction data in RPC response format 10 | sampleTx := `{"jsonrpc":"2.0","result":{"slot":303139093,"transaction":{"signatures":["3eNYyuFzJrqXwdC4VnZQpRRqv4nvgEf4U1jrQEmTVDgoTEx9aNJEPM3BcNAVTcw3bMHCyYAQVJfhpyXoyLPBFLA8"],"message":{"header":{"numRequiredSignatures":1,"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":9},"accountKeys":["H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX","BgMff4ZEtg6Apu83cHxiPZBioDmEusphusWwV1Jtk9nj","CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM","TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","8DCJfMMoHXCZZhVfnAy8f5zydcnV23CQ5UR63gasX1yh","ComputeBudget111111111111111111111111111111","ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","11111111111111111111111111111111","TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P","4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf","SysvarRent111111111111111111111111111111111","Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"],"recentBlockhash":"C5qJoMm4oEd4NH8f19wF8nGwFKvEx18awZ36Fm96VTVp","instructions":[{"programIdIndex":5,"accounts":[],"data":"HnkkG7","stackHeight":null},{"programIdIndex":5,"accounts":[],"data":"3QCwqmHZ4mdq","stackHeight":null},{"programIdIndex":6,"accounts":[0,1,0,7,8,9],"data":"","stackHeight":null},{"programIdIndex":10,"accounts":[11,2,7,3,4,1,0,8,9,12,13,10],"data":"AJTQ2h9DXrBdFY6uXSvVBBH6MbT4sCDYK","stackHeight":null}],"addressTableLookups":[]}},"meta":{"err":null,"status":{"Ok":null},"fee":255000,"preBalances":[103494654,0,357369713798981,21192140,2039280,1,731913600,1461600,1,934087680,1141440,58530000,1009200,40000000],"postBalances":[100917610,2039280,357369713801780,21472105,2039280,1,731913600,1461600,1,934087680,1141440,58530000,1009200,40000000],"innerInstructions":[{"index":2,"instructions":[{"programIdIndex":9,"accounts":[7],"data":"84eT","stackHeight":2},{"programIdIndex":8,"accounts":[0,1],"data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL","stackHeight":2},{"programIdIndex":9,"accounts":[1],"data":"P","stackHeight":2},{"programIdIndex":9,"accounts":[1,7],"data":"6dHTmbTMTZm6mynG47jWxdbTjuXbGJHiefLYF7XiBaZLV","stackHeight":2}]},{"index":3,"instructions":[{"programIdIndex":9,"accounts":[4,1,3],"data":"3DcCptZte3oM","stackHeight":2},{"programIdIndex":8,"accounts":[0,3],"data":"3Bxs4TANYoswz4Y7","stackHeight":2},{"programIdIndex":8,"accounts":[0,2],"data":"3Bxs4gqdzcC6NtK9","stackHeight":2},{"programIdIndex":10,"accounts":[13],"data":"2K7nL28PxCW8ejnyCeuMpbWojoBGexZs7tN3VavtnHif2axb1WwWnUMCTFK2UYA5QeYGR7fpUNLgjSWNKXt4AdbD3B3V44CneMw99Ni6EtaAQGbLbQr6rwNgWtUu5UAcaASx7tLf8SoGapmX1zc4RsB9LHMpd3dNDCf7H6SXCfeZk9rJ8a7424FZn4ej","stackHeight":2}]}],"logMessages":["Program ComputeBudget111111111111111111111111111111 invoke [1]","Program ComputeBudget111111111111111111111111111111 success","Program ComputeBudget111111111111111111111111111111 invoke [1]","Program ComputeBudget111111111111111111111111111111 success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]","Program log: Create","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: GetAccountDataSize","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 244333 compute units","Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program log: Initialize the associated token account","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: InitializeImmutableOwner","Program log: Please upgrade to SPL Token 2022 for immutable owner support","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 237746 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: InitializeAccount3","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 233864 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20307 of 249700 compute units","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]","Program log: Instruction: Buy","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: Transfer","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 210756 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 198668 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success","Program data: vdt/007mYe51DCMfJMDc1xzkzw+3T0/IL5MwvSeD8fHKYZ6ghuF0H51FBAAAAAAAAOQLVAIAAAAB7/l/o1AL9GidA3MroA1YLKkYNdzsyX8T6twPEOxQ29Jz1UFnAAAAADmDWP0GAAAAW+u01zrPAwA51zQBAAAAAFtTooup0AIA","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 34453 of 229393 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"],"preTokenBalances":[{"accountIndex":4,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":999286564.142939,"decimals":6,"amount":"999286564142939","uiAmountString":"999286564.142939"},"owner":"TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"}],"postTokenBalances":[{"accountIndex":1,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":10000.0,"decimals":6,"amount":"10000000000","uiAmountString":"10000"},"owner":"H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},{"accountIndex":4,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":999276564.142939,"decimals":6,"amount":"999276564142939","uiAmountString":"999276564.142939"},"owner":"TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"}],"rewards":[],"loadedAddresses":{"writable":[],"readonly":[]},"computeUnitsConsumed":55060},"version":0,"blockTime":1732367731},"id":0} 11 | ` 12 | 13 | // Call ParseTransactionGo 14 | result, err := _parseTransaction(sampleTx) 15 | if err != nil { 16 | t.Errorf("Failed to parse transaction: %v", err) 17 | return 18 | } 19 | 20 | // Verify the result is valid JSON 21 | var parsedResult interface{} 22 | err = json.Unmarshal([]byte(result), &parsedResult) 23 | if err != nil { 24 | t.Errorf("Failed to parse result JSON: %v", err) 25 | return 26 | } 27 | 28 | t.Logf("Successfully parsed transaction. Result: %s", result) 29 | } 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module sol-tx-parser-capi 2 | 3 | go 1.20 4 | 5 | require github.com/0xjeffro/tx-parser v0.4.2 6 | 7 | require ( 8 | filippo.io/edwards25519 v1.0.0-rc.1 // indirect 9 | github.com/blendle/zapdriver v1.3.1 // indirect 10 | github.com/davecgh/go-spew v1.1.1 // indirect 11 | github.com/fatih/color v1.9.0 // indirect 12 | github.com/gagliardetto/binary v0.8.0 // indirect 13 | github.com/gagliardetto/solana-go v1.11.0 // indirect 14 | github.com/gagliardetto/treeout v0.1.4 // indirect 15 | github.com/google/go-cmp v0.6.0 // indirect 16 | github.com/json-iterator/go v1.1.12 // indirect 17 | github.com/klauspost/compress v1.13.6 // indirect 18 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 19 | github.com/mattn/go-colorable v0.1.4 // indirect 20 | github.com/mattn/go-isatty v0.0.20 // indirect 21 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 22 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 23 | github.com/modern-go/reflect2 v1.0.2 // indirect 24 | github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect 25 | github.com/mr-tron/base58 v1.2.0 // indirect 26 | github.com/near/borsh-go v0.3.1 // indirect 27 | github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect 28 | go.mongodb.org/mongo-driver v1.11.0 // indirect 29 | go.uber.org/atomic v1.7.0 // indirect 30 | go.uber.org/multierr v1.6.0 // indirect 31 | go.uber.org/zap v1.21.0 // indirect 32 | golang.org/x/crypto v0.23.0 // indirect 33 | golang.org/x/sys v0.20.0 // indirect 34 | golang.org/x/term v0.20.0 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= 2 | filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= 3 | github.com/0xjeffro/tx-parser v0.4.2 h1:py3RQ9PgJmz9U12QAhhqirBhE+t+VcygdaRPFHjadFw= 4 | github.com/0xjeffro/tx-parser v0.4.2/go.mod h1:9fwFwe6j5iW3L2y7Zwv75aC9dHWtKJinQ+iCMLViI+I= 5 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 6 | github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 7 | github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= 8 | github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= 13 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 14 | github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg= 15 | github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= 16 | github.com/gagliardetto/solana-go v1.11.0 h1:g6mR7uRNVT0Y0LVR0bvJNfKV6TyO6oUzBYu03ZmkEmY= 17 | github.com/gagliardetto/solana-go v1.11.0/go.mod h1:afBEcIRrDLJst3lvAahTr63m6W2Ns6dajZxe2irF7Jg= 18 | github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= 19 | github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= 20 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 21 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 22 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 23 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 24 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 25 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 26 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 27 | github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 28 | github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= 29 | github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 30 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 31 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 32 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 33 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 34 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 35 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 36 | github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= 37 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 38 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 39 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 40 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 41 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 42 | github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= 43 | github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 44 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 45 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 46 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 47 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 48 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 49 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= 50 | github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= 51 | github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= 52 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 53 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 54 | github.com/near/borsh-go v0.3.1 h1:ukNbhJlPKxfua0/nIuMZhggSU8zvtRP/VyC25LLqPUA= 55 | github.com/near/borsh-go v0.3.1/go.mod h1:NeMochZp7jN/pYFuxLkrZtmLqbADmnp/y1+/dL+AsyQ= 56 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 57 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 58 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 59 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 60 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 61 | github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= 62 | github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 63 | github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= 64 | github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= 65 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 66 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 67 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 68 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 69 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 70 | github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= 71 | github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= 72 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 73 | github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= 74 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= 75 | github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= 76 | github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= 77 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 78 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 79 | go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= 80 | go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= 81 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 82 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 83 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 84 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 85 | go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 86 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 87 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= 88 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 89 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 90 | go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= 91 | go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= 92 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 93 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 94 | golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 95 | golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 96 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 97 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 98 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 99 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 100 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 101 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 102 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 103 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 104 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 105 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 106 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 107 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 108 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 109 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 110 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 111 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 112 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 113 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 114 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 115 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 116 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 117 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 118 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 119 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 120 | golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= 121 | golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= 122 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 123 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 124 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 125 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 126 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 127 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 128 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 129 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 130 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 131 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 132 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 133 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 134 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 135 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 136 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 137 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 138 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 139 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 140 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 141 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 142 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 143 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Solana Transaction Parser 2 | 3 | Python bindings for parsing Solana transactions using a Go-based C shared library. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | pip install solana-tx-parser 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```python 14 | import json 15 | from solana_tx_parser import parse_transaction 16 | 17 | tx_data = { 18 | "jsonrpc": "2.0", 19 | "result": ..., # Your transaction JSON string 20 | "id": 1, 21 | } 22 | tx_json = json.dumps(tx_data) 23 | result = parse_transaction(tx_json) 24 | ``` 25 | 26 | result is a list of transaction objects: 27 | 28 | ```python 29 | [ 30 | { 31 | "rawTx": {...}, # raw transaction data 32 | "accountList": [ 33 | "H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX", 34 | "BgMff4ZEtg6Apu83cHxiPZBioDmEusphusWwV1Jtk9nj", 35 | "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM", 36 | "TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA", 37 | "8DCJfMMoHXCZZhVfnAy8f5zydcnV23CQ5UR63gasX1yh", 38 | "ComputeBudget111111111111111111111111111111", 39 | "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", 40 | "8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump", 41 | "11111111111111111111111111111111", 42 | "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 43 | "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", 44 | "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf", 45 | "SysvarRent111111111111111111111111111111111", 46 | "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" 47 | ], 48 | "actions": [ 49 | { 50 | "programId": "ComputeBudget111111111111111111111111111111", 51 | "programName": "ComputeBudget", 52 | "instructionName": "SetComputeUnitLimit", 53 | "computeUnitLimit": 250000 54 | }, 55 | { 56 | "programId": "ComputeBudget111111111111111111111111111111", 57 | "programName": "ComputeBudget", 58 | "instructionName": "SetComputeUnitPrice", 59 | "microLamports": 1000000 60 | }, 61 | { 62 | "programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", 63 | "programName": "Unknown", 64 | "instructionName": "Unknown", 65 | "error": null 66 | }, 67 | { 68 | "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", 69 | "programName": "PumpFun", 70 | "instructionName": "Buy", 71 | "who": "H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX", 72 | "fromToken": "So11111111111111111111111111111111111111112", 73 | "fromTokenAmount": 279965, 74 | "toToken": "8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump", 75 | "toTokenAmount": 10000000000, 76 | "feeAmount": 2799 77 | } 78 | ] 79 | } 80 | ] 81 | ``` 82 | -------------------------------------------------------------------------------- /python/pdm.lock: -------------------------------------------------------------------------------- 1 | # This file is @generated by PDM. 2 | # It is not intended for manual editing. 3 | 4 | [metadata] 5 | groups = ["default"] 6 | strategy = ["cross_platform", "inherit_metadata"] 7 | lock_version = "4.4.2" 8 | content_hash = "sha256:74d1ff6340a177e751ed9224ce247722d68b2ef5328f916be683c57f9365f8c5" 9 | 10 | [[package]] 11 | name = "colorama" 12 | version = "0.4.6" 13 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 14 | summary = "Cross-platform colored terminal text." 15 | groups = ["default"] 16 | marker = "sys_platform == \"win32\"" 17 | files = [ 18 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 19 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 20 | ] 21 | 22 | [[package]] 23 | name = "exceptiongroup" 24 | version = "1.2.2" 25 | requires_python = ">=3.7" 26 | summary = "Backport of PEP 654 (exception groups)" 27 | groups = ["default"] 28 | marker = "python_version < \"3.11\"" 29 | files = [ 30 | {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, 31 | {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, 32 | ] 33 | 34 | [[package]] 35 | name = "iniconfig" 36 | version = "2.0.0" 37 | requires_python = ">=3.7" 38 | summary = "brain-dead simple config-ini parsing" 39 | groups = ["default"] 40 | files = [ 41 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 42 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 43 | ] 44 | 45 | [[package]] 46 | name = "packaging" 47 | version = "24.2" 48 | requires_python = ">=3.8" 49 | summary = "Core utilities for Python packages" 50 | groups = ["default"] 51 | files = [ 52 | {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, 53 | {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, 54 | ] 55 | 56 | [[package]] 57 | name = "pluggy" 58 | version = "1.5.0" 59 | requires_python = ">=3.8" 60 | summary = "plugin and hook calling mechanisms for python" 61 | groups = ["default"] 62 | files = [ 63 | {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, 64 | {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, 65 | ] 66 | 67 | [[package]] 68 | name = "pytest" 69 | version = "8.3.3" 70 | requires_python = ">=3.8" 71 | summary = "pytest: simple powerful testing with Python" 72 | groups = ["default"] 73 | dependencies = [ 74 | "colorama; sys_platform == \"win32\"", 75 | "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", 76 | "iniconfig", 77 | "packaging", 78 | "pluggy<2,>=1.5", 79 | "tomli>=1; python_version < \"3.11\"", 80 | ] 81 | files = [ 82 | {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, 83 | {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, 84 | ] 85 | 86 | [[package]] 87 | name = "tomli" 88 | version = "2.2.1" 89 | requires_python = ">=3.8" 90 | summary = "A lil' TOML parser" 91 | groups = ["default"] 92 | marker = "python_version < \"3.11\"" 93 | files = [ 94 | {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, 95 | {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, 96 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, 97 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, 98 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, 99 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, 100 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, 101 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, 102 | {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, 103 | {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, 104 | {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, 105 | {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, 106 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, 107 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, 108 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, 109 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, 110 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, 111 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, 112 | {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, 113 | {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, 114 | {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, 115 | {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, 116 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, 117 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, 118 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, 119 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, 120 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, 121 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, 122 | {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, 123 | {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, 124 | {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, 125 | {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, 126 | ] 127 | -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "solana-tx-parser" 3 | version = "0.0.5" 4 | description = "Python bindings for Solana Transaction Parser (tx-parser), enabling Python developers to easily parse and analyze Solana blockchain transactions. This package provides a high-performance C-API wrapper around the original Rust implementation, making blockchain data interpretation accessible in Python while maintaining native-like performance." 5 | authors = [ 6 | {name = "mkdir700", email = "mkdir700@gmail.com"}, 7 | ] 8 | dependencies = [] 9 | requires-python = ">=3.8" 10 | readme = "README.md" 11 | license = {text = "MIT"} 12 | classifiers = [ 13 | "Operating System :: MacOS", 14 | "Operating System :: POSIX :: Linux", 15 | "Operating System :: Microsoft :: Windows", 16 | ] 17 | 18 | [build-system] 19 | requires = ["pdm-backend"] 20 | build-backend = "pdm.backend" 21 | 22 | [tool.pdm.dev-dependencies] 23 | test = [ 24 | "pytest>=8.3.3", 25 | ] 26 | 27 | [tool.pdm.build] 28 | package-dir = "src" 29 | includes = [ 30 | "src/solana_tx_parser/**/*.py", # Python source files 31 | "src/solana_tx_parser/lib/*.so", # Linux 32 | "src/solana_tx_parser/lib/*.dylib", # macOS 33 | "src/solana_tx_parser/lib/*.dll", # Windows 34 | ] 35 | -------------------------------------------------------------------------------- /python/src/solana_tx_parser/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import parse_transaction 2 | 3 | __all__ = ["parse_transaction"] -------------------------------------------------------------------------------- /python/src/solana_tx_parser/parser.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import json 3 | import os 4 | import platform 5 | from typing import Any, Dict, List 6 | 7 | 8 | def _get_lib_path(): 9 | system = platform.system() 10 | lib_dir = os.path.join(os.path.dirname(__file__), "lib") 11 | 12 | if system == "Darwin": # macOS 13 | return os.path.join(lib_dir, "libsoltxparser.dylib") 14 | elif system == "Linux": # Linux 15 | return os.path.join(lib_dir, "libsoltxparser.so") 16 | elif system == "Windows": # Windows 17 | return os.path.join(lib_dir, "soltxparser.dll") 18 | else: 19 | raise OSError(f"Unsupported operating system: {system}") 20 | 21 | 22 | # Get the library path 23 | _lib_path = _get_lib_path() 24 | 25 | # Load the shared library 26 | _lib = ctypes.CDLL(_lib_path) 27 | 28 | 29 | class ParseResult(ctypes.Structure): 30 | _fields_ = [("error", ctypes.c_char_p), ("result", ctypes.c_char_p)] 31 | 32 | 33 | # Set function argument and return types 34 | _lib.ParseTransaction.argtypes = [ctypes.c_char_p] 35 | _lib.ParseTransaction.restype = ParseResult 36 | _lib.FreeParseResult.argtypes = [ParseResult] 37 | 38 | 39 | def parse_transaction(tx_data: str) -> List[Dict[str, Any]]: 40 | """Parse a Solana transaction. 41 | 42 | Args: 43 | tx_data: The transaction data as a string 44 | 45 | Returns: 46 | A dictionary containing the parsed transaction data 47 | 48 | Raises: 49 | RuntimeError: If parsing fails 50 | """ 51 | result = _lib.ParseTransaction(tx_data.encode("utf-8")) 52 | 53 | try: 54 | if result.error: 55 | raise RuntimeError(result.error.decode("utf-8")) 56 | 57 | if result.result: 58 | return json.loads(result.result.decode("utf-8")) 59 | 60 | raise RuntimeError("No result and no error") 61 | 62 | finally: 63 | _lib.FreeParseResult(result) 64 | 65 | 66 | if __name__ == "__main__": 67 | content = """ 68 | {"jsonrpc":"2.0","result":{"slot":303139093,"transaction":{"signatures":["3eNYyuFzJrqXwdC4VnZQpRRqv4nvgEf4U1jrQEmTVDgoTEx9aNJEPM3BcNAVTcw3bMHCyYAQVJfhpyXoyLPBFLA8"],"message":{"header":{"numRequiredSignatures":1,"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":9},"accountKeys":["H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX","BgMff4ZEtg6Apu83cHxiPZBioDmEusphusWwV1Jtk9nj","CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM","TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","8DCJfMMoHXCZZhVfnAy8f5zydcnV23CQ5UR63gasX1yh","ComputeBudget111111111111111111111111111111","ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","11111111111111111111111111111111","TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P","4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf","SysvarRent111111111111111111111111111111111","Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"],"recentBlockhash":"C5qJoMm4oEd4NH8f19wF8nGwFKvEx18awZ36Fm96VTVp","instructions":[{"programIdIndex":5,"accounts":[],"data":"HnkkG7","stackHeight":null},{"programIdIndex":5,"accounts":[],"data":"3QCwqmHZ4mdq","stackHeight":null},{"programIdIndex":6,"accounts":[0,1,0,7,8,9],"data":"","stackHeight":null},{"programIdIndex":10,"accounts":[11,2,7,3,4,1,0,8,9,12,13,10],"data":"AJTQ2h9DXrBdFY6uXSvVBBH6MbT4sCDYK","stackHeight":null}],"addressTableLookups":[]}},"meta":{"err":null,"status":{"Ok":null},"fee":255000,"preBalances":[103494654,0,357369713798981,21192140,2039280,1,731913600,1461600,1,934087680,1141440,58530000,1009200,40000000],"postBalances":[100917610,2039280,357369713801780,21472105,2039280,1,731913600,1461600,1,934087680,1141440,58530000,1009200,40000000],"innerInstructions":[{"index":2,"instructions":[{"programIdIndex":9,"accounts":[7],"data":"84eT","stackHeight":2},{"programIdIndex":8,"accounts":[0,1],"data":"11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL","stackHeight":2},{"programIdIndex":9,"accounts":[1],"data":"P","stackHeight":2},{"programIdIndex":9,"accounts":[1,7],"data":"6dHTmbTMTZm6mynG47jWxdbTjuXbGJHiefLYF7XiBaZLV","stackHeight":2}]},{"index":3,"instructions":[{"programIdIndex":9,"accounts":[4,1,3],"data":"3DcCptZte3oM","stackHeight":2},{"programIdIndex":8,"accounts":[0,3],"data":"3Bxs4TANYoswz4Y7","stackHeight":2},{"programIdIndex":8,"accounts":[0,2],"data":"3Bxs4gqdzcC6NtK9","stackHeight":2},{"programIdIndex":10,"accounts":[13],"data":"2K7nL28PxCW8ejnyCeuMpbWojoBGexZs7tN3VavtnHif2axb1WwWnUMCTFK2UYA5QeYGR7fpUNLgjSWNKXt4AdbD3B3V44CneMw99Ni6EtaAQGbLbQr6rwNgWtUu5UAcaASx7tLf8SoGapmX1zc4RsB9LHMpd3dNDCf7H6SXCfeZk9rJ8a7424FZn4ej","stackHeight":2}]}],"logMessages":["Program ComputeBudget111111111111111111111111111111 invoke [1]","Program ComputeBudget111111111111111111111111111111 success","Program ComputeBudget111111111111111111111111111111 invoke [1]","Program ComputeBudget111111111111111111111111111111 success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]","Program log: Create","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: GetAccountDataSize","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 244333 compute units","Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program log: Initialize the associated token account","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: InitializeImmutableOwner","Program log: Please upgrade to SPL Token 2022 for immutable owner support","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 237746 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: InitializeAccount3","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 233864 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20307 of 249700 compute units","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]","Program log: Instruction: Buy","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]","Program log: Instruction: Transfer","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 210756 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 198668 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success","Program data: vdt/007mYe51DCMfJMDc1xzkzw+3T0/IL5MwvSeD8fHKYZ6ghuF0H51FBAAAAAAAAOQLVAIAAAAB7/l/o1AL9GidA3MroA1YLKkYNdzsyX8T6twPEOxQ29Jz1UFnAAAAADmDWP0GAAAAW+u01zrPAwA51zQBAAAAAFtTooup0AIA","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 34453 of 229393 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"],"preTokenBalances":[{"accountIndex":4,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":999286564.142939,"decimals":6,"amount":"999286564142939","uiAmountString":"999286564.142939"},"owner":"TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"}],"postTokenBalances":[{"accountIndex":1,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":10000.0,"decimals":6,"amount":"10000000000","uiAmountString":"10000"},"owner":"H9m6fFpfGupwiJAY2aKd9d2MQe1StYSwxRNPcx2NHQuX","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},{"accountIndex":4,"mint":"8suSDnKVFRyAsTpZ7e2J2seofy6fVhL3cerTfyYppump","uiTokenAmount":{"uiAmount":999276564.142939,"decimals":6,"amount":"999276564142939","uiAmountString":"999276564.142939"},"owner":"TEf2o4WuA8RjzGK5SoE6kPLQzQE4gjrgp4tvErURicA","programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"}],"rewards":[],"loadedAddresses":{"writable":[],"readonly":[]},"computeUnitsConsumed":55060},"version":0,"blockTime":1732367731},"id":0} 69 | """ 70 | data = parse_transaction(content) 71 | print(json.dumps(data)) 72 | -------------------------------------------------------------------------------- /python/tests/examples/raydium_pool_v4_swap_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "blockTime": 1733393650, 3 | "meta": { 4 | "computeUnitsConsumed": 53274, 5 | "err": null, 6 | "fee": 205002, 7 | "innerInstructions": [ 8 | { 9 | "index": 2, 10 | "instructions": [ 11 | { 12 | "accounts": [9], 13 | "data": "84eT", 14 | "programIdIndex": 11, 15 | "stackHeight": 2 16 | }, 17 | { 18 | "accounts": [0, 1], 19 | "data": "11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL", 20 | "programIdIndex": 10, 21 | "stackHeight": 2 22 | }, 23 | { 24 | "accounts": [1], 25 | "data": "P", 26 | "programIdIndex": 11, 27 | "stackHeight": 2 28 | }, 29 | { 30 | "accounts": [1, 9], 31 | "data": "6MwZH6Px6qJXZj8tYueKo9WrrKfRVDHxJCdK88k4LkM36", 32 | "programIdIndex": 11, 33 | "stackHeight": 2 34 | } 35 | ] 36 | }, 37 | { 38 | "index": 3, 39 | "instructions": [ 40 | { 41 | "accounts": [5, 4, 0], 42 | "data": "3uyyT2PjqNNj", 43 | "programIdIndex": 11, 44 | "stackHeight": 2 45 | }, 46 | { 47 | "accounts": [3, 1, 13], 48 | "data": "3TfEAHDG6wy1", 49 | "programIdIndex": 11, 50 | "stackHeight": 2 51 | } 52 | ] 53 | } 54 | ], 55 | "loadedAddresses": { 56 | "readonly": [], 57 | "writable": [] 58 | }, 59 | "logMessages": [ 60 | "Program ComputeBudget111111111111111111111111111111 invoke [1]", 61 | "Program ComputeBudget111111111111111111111111111111 success", 62 | "Program ComputeBudget111111111111111111111111111111 invoke [1]", 63 | "Program ComputeBudget111111111111111111111111111111 success", 64 | "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]", 65 | "Program log: Create", 66 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", 67 | "Program log: Instruction: GetAccountDataSize", 68 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 94333 compute units", 69 | "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=", 70 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 71 | "Program 11111111111111111111111111111111 invoke [2]", 72 | "Program 11111111111111111111111111111111 success", 73 | "Program log: Initialize the associated token account", 74 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", 75 | "Program log: Instruction: InitializeImmutableOwner", 76 | "Program log: Please upgrade to SPL Token 2022 for immutable owner support", 77 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 87746 compute units", 78 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 79 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", 80 | "Program log: Instruction: InitializeAccount3", 81 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3158 of 83864 compute units", 82 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 83 | "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 19277 of 99700 compute units", 84 | "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", 85 | "Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [1]", 86 | "Program log: ray_log: A/JHdi4FAAAAAQAAAAAAAAABAAAAAAAAAAJJOCYGAgAAnswgeQoAAABbD7gYQVsBAFTnJwAAAAAA", 87 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", 88 | "Program log: Instruction: Transfer", 89 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 63028 compute units", 90 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 91 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", 92 | "Program log: Instruction: Transfer", 93 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 55402 compute units", 94 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 95 | "Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30632 of 80423 compute units", 96 | "Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success", 97 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]", 98 | "Program log: Instruction: CloseAccount", 99 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2915 of 49791 compute units", 100 | "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", 101 | "Program 11111111111111111111111111111111 invoke [1]", 102 | "Program 11111111111111111111111111111111 success" 103 | ], 104 | "postBalances": [ 105 | 184387854020, 0, 6124800, 44981289786, 2039280, 2039280, 2100675, 1, 106 | 731913600, 742524947309, 1, 934087680, 1141440, 13532449905, 3591360 107 | ], 108 | "postTokenBalances": [ 109 | { 110 | "accountIndex": 3, 111 | "mint": "So11111111111111111111111111111111111111112", 112 | "owner": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", 113 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 114 | "uiTokenAmount": { 115 | "amount": "44979250506", 116 | "decimals": 9, 117 | "uiAmount": 44.979250506, 118 | "uiAmountString": "44.979250506" 119 | } 120 | }, 121 | { 122 | "accountIndex": 4, 123 | "mint": "AaJ6gmTzaQw9zxfK6BD9N89wzZLuSuwTRbi8YrTCpump", 124 | "owner": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", 125 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 126 | "uiTokenAmount": { 127 | "amount": "381832376768333", 128 | "decimals": 6, 129 | "uiAmount": 381832376.768333, 130 | "uiAmountString": "381832376.768333" 131 | } 132 | }, 133 | { 134 | "accountIndex": 5, 135 | "mint": "AaJ6gmTzaQw9zxfK6BD9N89wzZLuSuwTRbi8YrTCpump", 136 | "owner": "orcACRJYTFjTeo2pV8TfYRTpmqfoYgbVi9GeANXTCc8", 137 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 138 | "uiTokenAmount": { 139 | "amount": "2203179942160", 140 | "decimals": 6, 141 | "uiAmount": 2203179.94216, 142 | "uiAmountString": "2203179.94216" 143 | } 144 | } 145 | ], 146 | "preBalances": [ 147 | 184386443918, 0, 6124800, 44983904910, 2039280, 2039280, 1100655, 1, 148 | 731913600, 742524947309, 1, 934087680, 1141440, 13532449905, 3591360 149 | ], 150 | "preTokenBalances": [ 151 | { 152 | "accountIndex": 3, 153 | "mint": "So11111111111111111111111111111111111111112", 154 | "owner": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", 155 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 156 | "uiTokenAmount": { 157 | "amount": "44981865630", 158 | "decimals": 9, 159 | "uiAmount": 44.98186563, 160 | "uiAmountString": "44.98186563" 161 | } 162 | }, 163 | { 164 | "accountIndex": 4, 165 | "mint": "AaJ6gmTzaQw9zxfK6BD9N89wzZLuSuwTRbi8YrTCpump", 166 | "owner": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", 167 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 168 | "uiTokenAmount": { 169 | "amount": "381810122428251", 170 | "decimals": 6, 171 | "uiAmount": 381810122.428251, 172 | "uiAmountString": "381810122.428251" 173 | } 174 | }, 175 | { 176 | "accountIndex": 5, 177 | "mint": "AaJ6gmTzaQw9zxfK6BD9N89wzZLuSuwTRbi8YrTCpump", 178 | "owner": "orcACRJYTFjTeo2pV8TfYRTpmqfoYgbVi9GeANXTCc8", 179 | "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 180 | "uiTokenAmount": { 181 | "amount": "2225434282242", 182 | "decimals": 6, 183 | "uiAmount": 2225434.282242, 184 | "uiAmountString": "2225434.282242" 185 | } 186 | } 187 | ], 188 | "rewards": [], 189 | "status": { 190 | "Ok": null 191 | } 192 | }, 193 | "slot": 305539244, 194 | "transaction": { 195 | "message": { 196 | "accountKeys": [ 197 | "orcACRJYTFjTeo2pV8TfYRTpmqfoYgbVi9GeANXTCc8", 198 | "H2AuE7NVmJ1TtqsWWfSaNh5S7TLk7j5vwzkpXu7VnDbA", 199 | "FrSpBqMa6MbEt4EY9CvPdM6Ycuc5wRYCdNcDMxgSznLz", 200 | "DfXYzvmP9JgF7JxMbipDcx9rSoB5fzodAaYEr1ScJ3bG", 201 | "DB7bz74FypSXqwsAh8q2pEp4LjCbi9NpKdViCCof4aim", 202 | "AarSAVG8DLJ27HYAy5GNmz2RAKzNWx5qk85AVUG3Vas3", 203 | "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", 204 | "ComputeBudget111111111111111111111111111111", 205 | "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", 206 | "So11111111111111111111111111111111111111112", 207 | "11111111111111111111111111111111", 208 | "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 209 | "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", 210 | "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", 211 | "5m2GnfN5ma2R64xMf1R8ciHNzVv8HbCBZNCDyHBXChxr" 212 | ], 213 | "addressTableLookups": [], 214 | "header": { 215 | "numReadonlySignedAccounts": 0, 216 | "numReadonlyUnsignedAccounts": 8, 217 | "numRequiredSignatures": 1 218 | }, 219 | "instructions": [ 220 | { 221 | "accounts": [], 222 | "data": "3eJMY7mcBi9m", 223 | "programIdIndex": 7, 224 | "stackHeight": null 225 | }, 226 | { 227 | "accounts": [], 228 | "data": "JC3gyu", 229 | "programIdIndex": 7, 230 | "stackHeight": null 231 | }, 232 | { 233 | "accounts": [0, 1, 0, 9, 10, 11], 234 | "data": "", 235 | "programIdIndex": 8, 236 | "stackHeight": null 237 | }, 238 | { 239 | "accounts": [ 240 | 11, 2, 13, 14, 3, 4, 14, 14, 14, 14, 14, 14, 14, 14, 5, 1, 0 241 | ], 242 | "data": "6RRg4WiFngE5NtxBuqnEfbV", 243 | "programIdIndex": 12, 244 | "stackHeight": null 245 | }, 246 | { 247 | "accounts": [1, 0, 0], 248 | "data": "A", 249 | "programIdIndex": 11, 250 | "stackHeight": null 251 | }, 252 | { 253 | "accounts": [0, 6], 254 | "data": "3Bxs4Ex4wq3eMLMV", 255 | "programIdIndex": 10, 256 | "stackHeight": null 257 | } 258 | ], 259 | "recentBlockhash": "9gS6fP4QuxbFdCzL1gfc1n776v37agKK1wsyer5yzzKq" 260 | }, 261 | "signatures": [ 262 | "2XgzfkWeDeua4oemWXrj3JzhxVsV4mGsqVZfETSbhn6hGFuLvi2fjdK2TGcmuQQnZSEjUmMmPjUnCFWDebGJcgWQ" 263 | ] 264 | }, 265 | "version": 0 266 | } 267 | -------------------------------------------------------------------------------- /python/tests/test_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | import pytest 5 | 6 | from solana_tx_parser import parse_transaction 7 | 8 | cur = Path(__file__).parent 9 | examples = cur / "examples" 10 | 11 | 12 | # 使用 pytest 从 examples 目录下读取所有的 json 文件,并且测试每个文件的解析结果 13 | @pytest.mark.parametrize("file", examples.glob("*.json")) 14 | def test_parse_transaction(file): 15 | with open(file, "r") as f: 16 | sample_tx = f.read() 17 | 18 | data = json.loads(sample_tx) 19 | if "id" not in data: 20 | data = {"jsonrpc": "2.0", "result": data, "id": 0} 21 | 22 | result = parse_transaction(json.dumps(data)) 23 | try: 24 | assert result is not None 25 | assert result[0]["actions"] is not None 26 | finally: 27 | print(f"Failed to parse {file.name}") 28 | --------------------------------------------------------------------------------