{"id":18375739,"url":"https://github.com/factomproject/factom-api","last_synced_at":"2025-04-06T20:31:10.250Z","repository":{"id":57428169,"uuid":"113649579","full_name":"FactomProject/factom-api","owner":"FactomProject","description":"Python client library for the Factom API","archived":false,"fork":false,"pushed_at":"2020-10-23T03:29:22.000Z","size":247,"stargazers_count":19,"open_issues_count":0,"forks_count":8,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-04-26T11:22:35.888Z","etag":null,"topics":["api-client","blockchain","cryptocurrency","factoids","factom","factom-api","factom-walletd","factomd","fct","python","python3","wallet"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FactomProject.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-09T07:00:25.000Z","updated_at":"2024-01-19T10:25:03.000Z","dependencies_parsed_at":"2022-09-02T18:30:40.225Z","dependency_job_id":null,"html_url":"https://github.com/FactomProject/factom-api","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FactomProject%2Ffactom-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FactomProject%2Ffactom-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FactomProject%2Ffactom-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FactomProject%2Ffactom-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FactomProject","download_url":"https://codeload.github.com/FactomProject/factom-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247547286,"owners_count":20956530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","blockchain","cryptocurrency","factoids","factom","factom-api","factom-walletd","factomd","fct","python","python3","wallet"],"created_at":"2024-11-06T00:20:05.900Z","updated_at":"2025-04-06T20:31:09.983Z","avatar_url":"https://github.com/FactomProject.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# factom-api\n\n![CircleCI](https://img.shields.io/circleci/build/github/FactomProject/factom-api)\n![PyPI](https://img.shields.io/pypi/v/factom-api)\n\nThis library provides Python clients for interacting with the factomd and factom-walletd APIs. While not all API methods have been implemented yet, you'll find most of what you need to build a working application are available, along with shortcut methods for accomplishing common tasks involving multiple calls between the wallet and daemon.\n\nThis API client (from version 1.2 onwards) supports Python 3.5 and higher.\n\nIf you're unfamiliar with Factom, I encourage you to [read the documentation](http://docs.factom.com/), especially the [white paper](https://github.com/FactomProject/FactomDocs/blob/master/whitepaper.md). In a nutshell, Factom provides a layer on top of the Bitcoin blockchain making it possible to secure data faster and in larger amounts than the Bitcoin network would allow alone.\n\n## Getting started\n\n### Installing the API client\n\nThe easiest way to install is directly from pip:\n\n```\n$ pip install factom-api\n```\n\n## Usage\n\nI'll go over a few common operations here you'll most likely use in applications. In general you'll need instances of both the wallet and factomd clients to build and submit transactions. To build new clients:\n\n```python\nfrom factom import Factomd, FactomWalletd\n\n# Default settings\nfactomd = Factomd()\nwalletd = FactomWalletd()\n\n# You can also specify default fct and ec addresses, change host, or specify RPC credentials, for example:\nfct_address = 'FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q'\nec_address = 'EC2jhmCtabeTXGtuLi3AaPzvwSuqksdVsjfxXMXV5gPmipXc4GjC'\n\nfactomd = Factomd(\n    host='http://someotherhost:8088',\n    fct_address=fct_address,\n    ec_address=ec_address,\n    username='rpc_username',\n    password='rpc_password'\n)\n```\n\n### Transacting factoids to factoids\n\nFirst let's query the balance in both of our fct addresses:\n\n```python\n\u003e\u003e\u003e fct_address1 = 'FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q'\n\u003e\u003e\u003e fct_address2 = 'FA3TMQHrCrmLa4F9t442U3Ab3R9sM1gThYMDoygPEVtxrbHtFRtg'\n\u003e\u003e\u003e ec_address = 'EC2jhmCtabeTXGtuLi3AaPzvwSuqksdVsjfxXMXV5gPmipXc4GjC'\n\n# Initialize the two clients\n\u003e\u003e\u003e factomd = Factomd()\n\u003e\u003e\u003e walletd = FactomWalletd()\n\n# Query the balance in our first address. There should be a large amount\n\u003e\u003e\u003e factomd.factoid_balance(fct_address1)\n{'balance': 1999999735950}\n\n# The second address should be empty.\n\u003e\u003e\u003e factomd.factoid_balance(fct_address2)\n{'balance': 0}\n```\n\nThe wallet client provides a shorcut method `fct_to_fct()` which performs all the API calls needed to submit a simple fct to fct transaction. This includes adding inputs and outputs, calculating the fee, building the signed transaction, and submitting it to the network.\n\n```python\n\u003e\u003e\u003e walletd.fct_to_fct(factomd, 50000, fct_to=fct_address2, fct_from=fct_address1)\n{'message': 'Successfully submitted the transaction', 'txid': 'a4d641f13d82b1d1682549d44fa41c7e1b01f1a16f8cbddb5c695df53fcebfd7'}\n```\n\nThe server reports the transaction was submitted and if we wait a few seconds we can see the results:\n\n```python\n\u003e\u003e\u003e factomd.factoid_balance(fct_address2)\n{'balance': 50000}\n```\n\n### Converting factoids to entry credits\n\nOur new entry credit address should have a balance of zero:\n\n```python\n\u003e\u003e\u003e factomd.entry_credit_balance(ec_address)\n{'balance': 0}\n```\n\nFirst, we need to ask for the conversion rate:\n\n```python\n\u003e\u003e\u003e factomd.entry_credit_rate()\n{'rate': 1000}\n```\n\nThis tells us we'll need to burn 1000 factoids in exchange for 1 entry credit, so let's purchase 50 entry credits for 50000 factoids. Similar to `fct_to_fct()`, the wallet client also provides a `fct_to_ec()` shortcut for building and submitting simple fct conversion transactions.\n\n```python\n\u003e\u003e\u003e walletd.fct_to_ec(factomd, 50000, fct_address=fct_address1, ec_address=ec_address)\n{'message': 'Successfully submitted the transaction', 'txid': 'd70b14ce05a21dbf772d1894383694b4537e17454915fc42dc20f02c1e0e2df2'}\n```\n\nAnd if we query our entry credit balance we see the conversion has happened:\n\n```python\n\u003e\u003e\u003e factomd.entry_credit_balance(ec_address)\n{'balance': 50}\n```\n\n### Writing chains and entries\n\nThe real meat and potatoes is the ability to easily read from and write data to the blockchain. Let's write some test data. The wallet client provides a `new_chain()` shortcut method that handles the API calls and encoding needed for creating a new chain. You could also build the transaction manually if you'd like more control over each step, but for most cases this is going to be easier.\n\n```python\n\u003e\u003e\u003e walletd.new_chain(factomd, ['random', 'chain', 'id'], 'chain_content', ec_address=ec_address)\n{'message': 'Entry Reveal Success', 'entryhash': 'f9662a4675f4bb6566337eafd8237ab9fd2ba396947dadeb677c0526d367a5ce', 'chainid': 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495'}\n```\n\nIf we wait a few minutes and search for the chain ID in the explorer we can see our initial entry:\n\n![Our new chain](screenshots/chain.png \"Our new chain\")\n\nNow let's add another entry to the same chain:\n\n```python\n\u003e\u003e\u003e chain_id = 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495'\n\u003e\u003e\u003e walletd.new_entry(factomd, chain_id, ['random', 'entry', 'id'], 'entry_content', ec_address=ec_address)\n{'message': 'Entry Reveal Success', 'entryhash': '96f0472c9ec8a76c861fb4df37beb742938f41bbe492dc04893337bf387b83c5', 'chainid': 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495'}\n```\n\nYou should see the new entry appear shortly.\n\n### Reading entries\n\nIf the entries in your chain reference each other, you may want to scan the entire chain in order to verify its integrity. The factomd client provides a `read_chain()` method which iterates over all entry-containing blocks and returns a list of entries in reverse order.\n\n```python\n\u003e\u003e\u003e chain_id = 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495'\n\u003e\u003e\u003e factomd.read_chain(chain_id)\n[{'chainid': 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495', 'extids': ['random', 'entry', 'id'], 'content': 'entry_content'}, {'chainid': 'da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495', 'extids': ['random', 'chain', 'id'], 'content': 'chain_content'}]\n```\n\nYou can see the two entries we created earlier.\n\n### Error handling\n\nWhen things go badly, API methods will raise a `factom.exceptions.FactomAPIError` with details about the error.\n\n```python\n\u003e\u003e\u003e walletd.new_chain(factomd, ['random', 'chain', 'id'], 'chain_content', ec_address=ec_address)\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  File \"/src/factom/client.py\", line 196, in new_chain\n    'ecpub': ec_address or self.ec_address\n  File \"/src/factom/client.py\", line 56, in _request\n    handle_error_response(resp)\n  File \"/src/factom/exceptions.py\", line 18, in handle_error_response\n    raise codes[code](message=message, code=code, data=data, response=resp)\nfactom.exceptions.InvalidParams: -32602: Invalid params\n```\n\nMore data about the error is attached to the exception instance:\n\n```python\n\u003e\u003e\u003e try:\n...     walletd.new_chain(factomd, ['random', 'chain', 'id'], 'chain_content', ec_address=ec_address)\n... except FactomAPIError as e:\n...     print(e.data)\n...\nChain da2ffed0ae7b33acc718089edc0f1d001289857cc27a49b6bc4dd22fac971495 already exists\n```\n\nIf you'd like to catch more specific errors, there are exception subclasses for the different error codes returned by the APIs. See [factom/exceptions.py](factom/exceptions.py) for a list.\n\n### Listening to LiveFeed\n\nThe LiveFeed in factomd pipes out data corresponding to various network events and pieces of work that were accomplished, such as processing an entry or sealing a directory block. The `factom.livefeed.LiveFeedShovel` class listens to the LiveFeed and handles that data in some way. As an example, if you had JSON output turned on for the LiveFeed:\n\n```python\nimport logging\nimport time\nfrom factom.livefeed.listener import LiveFeedListener\n\n\ndef log_event(event_payload: bytes):\n    logging.info(f\"Event: {event_payload.decode()}\")\n\n\nlistener = LiveFeedListener(handle=log_event)\n\nwhile True:\n    try:\n        listener.run()\n    except ConnectionResetError:\n        logging.warning(\"Connection reset by peer. Sleeping 5 seconds and restarting...\")\n        time.sleep(5)\n    except KeyboardInterrupt:\n        logging.info(\"KeyboardInterrupt received, shutting down...\")\n        break\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffactomproject%2Ffactom-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffactomproject%2Ffactom-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffactomproject%2Ffactom-api/lists"}