├── .gitignore ├── .soroban └── network │ └── standalone.toml ├── .vscode └── launch.json ├── README.md ├── aula01 ├── 00.jpg ├── 01.jpg ├── 02.jpg ├── 03.jpg ├── 04.jpg ├── 05.jpg ├── 06.jpg ├── 07.jpg ├── 08.jpg ├── 09.jpg ├── 10.jpg └── 11.jpg ├── aula02 ├── README.md ├── sdk │ ├── buy-sell │ │ └── main.py │ ├── liquidity-pool │ │ └── main.py │ ├── payment │ │ ├── main.py │ │ ├── transfer.py │ │ ├── utils.py │ │ └── wallet.py │ ├── poetry.lock │ ├── pyproject.toml │ └── token │ │ ├── main.py │ │ ├── tokens.py │ │ ├── utils.py │ │ └── wallet.py └── setup-node │ ├── docker-compose.yaml │ ├── prometheus.yml │ └── stellar_dashboard.json ├── aula03 ├── .soroban │ ├── contract-ids │ │ └── .gitkeep │ └── network │ │ └── home.toml ├── README.md ├── learn │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── memory_manager │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rustc │ ├── lib.rs │ ├── main │ └── main.rs └── soroban-smartcontracts │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── contracts │ └── hello_world │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── test.rs ├── aula04 ├── README.md └── soroban-smartcontracts │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── contracts │ ├── flipper │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── multiple_flips_test.1.json │ │ ├── simple_test.1.json │ │ └── test.1.json │ ├── increment │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── multiple_increments_test.1.json │ │ ├── simple_test.1.json │ │ └── test.1.json │ └── task_manager │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── test.rs └── aula05 ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── contracts └── token ├── Cargo.toml └── src ├── admin.rs ├── allowance.rs ├── balance.rs ├── contract.rs ├── lib.rs ├── metadata.rs ├── storage_types.rs └── test.rs /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | target/ 3 | .idea 4 | test_snapshots/ -------------------------------------------------------------------------------- /.soroban/network/standalone.toml: -------------------------------------------------------------------------------- 1 | rpc_url = "http://localhost:8000/soroban/rpc" 2 | network_passphrase = "Standalone Network ; February 2017" 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python Debugger: Current File", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal", 13 | "justMyCode": false 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stellar Bootcamp 2 | 3 | ## Aula 1 4 | 5 | - O que é DeFi? O que é economia tokenizada? 6 | - O que são tokens, Assets e criptomoedas? 7 | - Como funcinoa a web3? como a Stellar se encaixa? 8 | - Tokeneconomics Stellar, principais DeFi. 9 | - Blockchain low-level: wallet, tx, blocks, consenso, smartcontracts 10 | 11 | ## Aula 2 12 | 13 | - Fundamentos sobre Stellar. 14 | - Configurando fullnode e DevOps 15 | - Interagindo com o fullnode usando SDK. 16 | 17 | ## Aula 3 18 | 19 | - Ecosistema de sistema de desenvolvimento Rust 20 | - Básico sobre Rust 21 | - Básico de smartcontrats Soroban (Hello World) 22 | 23 | ## Aula 4 24 | 25 | - Flipando bits (Flipper) 26 | - Entendo sobre armazenamento (Counter) 27 | - Avançando em lógica (Task manager) 28 | 29 | ## Aula 5 30 | 31 | - Noções avançadas de Soroban 32 | -------------------------------------------------------------------------------- /aula01/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/00.jpg -------------------------------------------------------------------------------- /aula01/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/01.jpg -------------------------------------------------------------------------------- /aula01/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/02.jpg -------------------------------------------------------------------------------- /aula01/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/03.jpg -------------------------------------------------------------------------------- /aula01/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/04.jpg -------------------------------------------------------------------------------- /aula01/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/05.jpg -------------------------------------------------------------------------------- /aula01/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/06.jpg -------------------------------------------------------------------------------- /aula01/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/07.jpg -------------------------------------------------------------------------------- /aula01/08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/08.jpg -------------------------------------------------------------------------------- /aula01/09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/09.jpg -------------------------------------------------------------------------------- /aula01/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/10.jpg -------------------------------------------------------------------------------- /aula01/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula01/11.jpg -------------------------------------------------------------------------------- /aula02/README.md: -------------------------------------------------------------------------------- 1 | # 0. Blockchain paths 2 | 3 | - core blockchain engineer -> node 4 | * redes, criptografia, protocolo de consenso, DevOps 5 | 6 | - SDK engineer -> SDK 7 | * python, javascript, rust, ruby, golang 8 | 9 | - smartcontract engineer -> smartcontract 10 | * EVM: solidity, vyper | no-EVM: Rust, Golang 11 | 12 | - integration web3 engine -> application 13 | * lib (SDK): web3js, etherjs, viem | cardano SDK 14 | 15 | # 1. Como funciona o Ecosistema Stellar? 16 | 17 | - Nodes (Consenso) 18 | - SDK (Horizon) 19 | - Soroban (Smartcontacts) 20 | - Wallet (Freighter) 21 | 22 | # 2. Instalar ferramentas 23 | 24 | - Docker 25 | - Python 26 | 27 | 28 | # 3. Configurarr um node para desenvolvimento 29 | 30 | **Deploy do Node via Docker** 31 | 32 | ``` 33 | docker run \ 34 | --rm \ 35 | -p 8000:8000 \ 36 | --name stellar \ 37 | stellar/quickstart:testing \ 38 | --local \ 39 | --enable-soroban-rpc 40 | ``` 41 | 42 | **Deploy do [Node + Prometheus + Grafana] via Docker Compose** 43 | 44 | - [docker-compose.yaml](./setup-node/docker-compose.yaml) 45 | 46 | # 4. Usando o SDK para criar contas e fazer um pagamento 47 | 48 | - Como criar uma conta 49 | - Como criar uma transação 50 | 51 | # 5. Usando SDK para criar um Token 52 | 53 | - Emissor e Distribuidor 54 | - Criando o Token 55 | - Destribuindo o Token 56 | 57 | # 6. Criando um Pool de Liquidez 58 | 59 | - Tipos de transações 60 | 61 | # 7. Executando ordens de compra e venda 62 | 63 | - Colocando uma ordem de venda 64 | - Colocando uma ordem de compra 65 | - Validando saldos nas carteiras 66 | -------------------------------------------------------------------------------- /aula02/sdk/buy-sell/main.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula02/sdk/buy-sell/main.py -------------------------------------------------------------------------------- /aula02/sdk/liquidity-pool/main.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula02/sdk/liquidity-pool/main.py -------------------------------------------------------------------------------- /aula02/sdk/payment/main.py: -------------------------------------------------------------------------------- 1 | from utils import get_faucet, get_ledger_by_sequence, get_transaction_by_hash 2 | from wallet import create_alice_wallet, create_bob_wallet 3 | from transfer import transfer_from 4 | from stellar_sdk import Server 5 | 6 | 7 | print("✅ # Start Payment from Alice to Bob with amount 100XML") 8 | 9 | 10 | print("✅ # Configure the server for the Standalone network (local)") 11 | server = Server(horizon_url="http://localhost:8000") 12 | 13 | 14 | # criar carteiras 15 | alice = create_alice_wallet() 16 | bob = create_bob_wallet() 17 | 18 | 19 | # depositar nas carteiras 20 | get_faucet(alice.public_key, server) 21 | get_faucet(bob.public_key, server) 22 | 23 | 24 | # fazer transferencia 25 | tx_hash = transfer_from(alice, bob.public_key, 1000, server) 26 | 27 | 28 | # Buscar transação 29 | transaction = get_transaction_by_hash(server, tx_hash) 30 | 31 | 32 | # Buscar bloco da transação 33 | ledger_sequence = transaction["ledger"] 34 | ledger = get_ledger_by_sequence(server, ledger_sequence) 35 | 36 | -------------------------------------------------------------------------------- /aula02/sdk/payment/transfer.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Asset, Network, Server, TransactionBuilder, Keypair 2 | from utils import check_balances 3 | 4 | 5 | def transfer_from(sender: Keypair, receiver, amount, server: Server): 6 | print("✅ # Initial Sender's balances") 7 | check_balances(server, sender.public_key) 8 | 9 | print("✅ # Initial Receiver's balances") 10 | check_balances(server, receiver) 11 | 12 | print("✅ # Set the base fee") 13 | try: 14 | fee = server.fetch_base_fee() 15 | except Exception as e: 16 | print(f"Failed to fetch base fee: {e}") 17 | fee = 100 18 | 19 | sender_account = server.load_account(sender.public_key) 20 | 21 | print("✅ # Build transaction") 22 | transaction = ( 23 | TransactionBuilder( 24 | network_passphrase=Network.STANDALONE_NETWORK_PASSPHRASE, 25 | source_account=sender_account, 26 | base_fee=fee, 27 | ) 28 | .add_text_memo("Happy birthday!") 29 | .append_payment_op( 30 | destination=receiver, asset=Asset.native(), amount=str(amount) 31 | ) 32 | .set_timeout(60) 33 | .build() 34 | ) 35 | 36 | print("✅ # Sign the transaction with Sender's secret key") 37 | transaction.sign(sender.secret) 38 | 39 | print("✅ # Submits the transaction to the Horizon server") 40 | response = server.submit_transaction(transaction) 41 | tx_hash = response["hash"] 42 | print(f"✅ # Transaction Hash: {tx_hash}") 43 | 44 | print("✅ # Final Sender's balances") 45 | check_balances(server, sender.public_key) 46 | 47 | print("✅ # Final Receiver's balances") 48 | check_balances(server, receiver) 49 | 50 | print("✅ # Done!") 51 | 52 | return tx_hash 53 | -------------------------------------------------------------------------------- /aula02/sdk/payment/utils.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk.exceptions import NotFoundError 2 | from requests import get, RequestException 3 | 4 | 5 | def soft_create_account(public_key): 6 | url = "http://localhost:8000/friendbot" 7 | params = {"addr": public_key} 8 | timeout = 30 9 | try: 10 | r = get(url, params=params, timeout=timeout) 11 | r.raise_for_status() 12 | except RequestException as e: 13 | raise ValueError(f"Error in get faucet: {str(e)}") from e 14 | 15 | 16 | def validate_wallet(public_key, server): 17 | try: 18 | server.load_account(public_key) 19 | except NotFoundError: 20 | print("The destination account does not exist!") 21 | print("Creating Account!") 22 | soft_create_account(public_key) 23 | 24 | 25 | def validate_wallet_balance(public_key, server): 26 | try: 27 | r = server.accounts().account_id(public_key).call() 28 | except Exception as e: 29 | raise Exception(f"Error in getting account data: {str(e)}") from e 30 | 31 | for balance in r["balances"]: 32 | if balance["asset_type"] == "native": 33 | return float(balance["balance"]) > 0 34 | 35 | 36 | def check_balances(server, public_key): 37 | account = server.accounts().account_id(public_key).call() 38 | balances = account["balances"] 39 | print(f"✅ # Balances for account {public_key}:", end=": ") 40 | for balance in balances: 41 | asset_type = balance["asset_type"] 42 | balance_amount = balance["balance"] 43 | print(f"Asset Type: {asset_type}, Balance: {balance_amount}") 44 | 45 | 46 | def get_faucet(public_key, server): 47 | print(f"✅ # Try deposit 10.000XML to {public_key}") 48 | 49 | validate_wallet(public_key, server) 50 | if validate_wallet_balance(public_key, server): 51 | print(f"Wallet: {public_key} already balance!") 52 | return 53 | 54 | print(f"Wallet: {public_key} need a deposit!") 55 | 56 | soft_create_account(public_key) 57 | 58 | 59 | def get_transaction_by_hash(server, transaction_hash): 60 | transaction = server.transactions().transaction(transaction_hash).call() 61 | print("✅ # Transaction details:") 62 | print(f" - ID: {transaction['id']}") 63 | print(f" - Hash: {transaction['hash']}") 64 | print(f" - Ledger: {transaction['ledger']}") 65 | print(f" - Created At: {transaction['created_at']}") 66 | print(f" - Source Account: {transaction['source_account']}") 67 | print(f" - Memo: {transaction['memo']}") 68 | print(f" - Fee Charged: {transaction['fee_charged']}") 69 | print(f" - Operation Count: {transaction['operation_count']}") 70 | print(f" - Successful: {transaction['successful']}") 71 | 72 | return transaction 73 | 74 | 75 | def get_ledger_by_sequence(server, sequence): 76 | ledger = server.ledgers().ledger(sequence).call() 77 | print("✅ # Ledger details:") 78 | print(f" - Sequence: {ledger['sequence']}") 79 | print(f" - Hash: {ledger['hash']}") 80 | print(f" - Previous Hash: {ledger['prev_hash']}") 81 | print(f" - Transaction Count: {ledger['successful_transaction_count']}") 82 | print(f" - Operation Count: {ledger['operation_count']}") 83 | print(f" - Closed At: {ledger['closed_at']}") 84 | print(f" - Total Coins: {ledger['total_coins']}") 85 | print(f" - Fee Pool: {ledger['fee_pool']}") 86 | print(f" - Base Fee in Stroops: {ledger['base_fee_in_stroops']}") 87 | print(f" - Base Reserve in Stroops: {ledger['base_reserve_in_stroops']}") 88 | print(f" - Max Transaction Set Size: {ledger['max_tx_set_size']}") 89 | print(f" - Protocol Version: {ledger['protocol_version']}") 90 | 91 | return ledger 92 | -------------------------------------------------------------------------------- /aula02/sdk/payment/wallet.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Keypair 2 | 3 | 4 | def create_alice_wallet(): 5 | print("✅ # Alice's wallet created (SENDER)") 6 | alice_secret_key = "SAKKTW5AEJO7Y5DOGUKINE6NF55CR37OWK3WIX4JWQ7LHOOUIH2VQYR4" 7 | alice = Keypair.from_secret(alice_secret_key) 8 | assert alice.public_key == "GBTIDN5UQ3P4HT3CSIEYU55F6INXOMYOTU6U5KM67QMXPPUCTABT35U5" 9 | 10 | return alice 11 | 12 | 13 | def create_bob_wallet(): 14 | print("✅ # Bob's wallet created (RECEIVER)") 15 | bob_secret_key = "SCHBR3CYVBCN4DKDML5VKMAP3Q7B7XN6ARI34UHCOEBHLMNXEUTGIXI5" 16 | bob = Keypair.from_secret(bob_secret_key) 17 | assert bob.public_key == "GCGRVQLR2BKLNP3XP3N2R47Z52X2OIBC7QVZUI4LAZYXRRVIN5TP5GVJ" 18 | 19 | return bob 20 | -------------------------------------------------------------------------------- /aula02/sdk/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "annotated-types" 5 | version = "0.7.0" 6 | description = "Reusable constraint types to use with typing.Annotated" 7 | optional = false 8 | python-versions = ">=3.8" 9 | files = [ 10 | {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, 11 | {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, 12 | ] 13 | 14 | [[package]] 15 | name = "certifi" 16 | version = "2024.2.2" 17 | description = "Python package for providing Mozilla's CA Bundle." 18 | optional = false 19 | python-versions = ">=3.6" 20 | files = [ 21 | {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, 22 | {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, 23 | ] 24 | 25 | [[package]] 26 | name = "cffi" 27 | version = "1.16.0" 28 | description = "Foreign Function Interface for Python calling C code." 29 | optional = false 30 | python-versions = ">=3.8" 31 | files = [ 32 | {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, 33 | {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, 34 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, 35 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, 36 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, 37 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, 38 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, 39 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, 40 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, 41 | {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, 42 | {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, 43 | {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, 44 | {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, 45 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, 46 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, 47 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, 48 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, 49 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, 50 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, 51 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, 52 | {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, 53 | {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, 54 | {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, 55 | {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, 56 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, 57 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, 58 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, 59 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, 60 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, 61 | {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, 62 | {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, 63 | {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, 64 | {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, 65 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, 66 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, 67 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, 68 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, 69 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, 70 | {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, 71 | {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, 72 | {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, 73 | {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, 74 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, 75 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, 76 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, 77 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, 78 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, 79 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, 80 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, 81 | {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, 82 | {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, 83 | {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, 84 | ] 85 | 86 | [package.dependencies] 87 | pycparser = "*" 88 | 89 | [[package]] 90 | name = "charset-normalizer" 91 | version = "3.3.2" 92 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 93 | optional = false 94 | python-versions = ">=3.7.0" 95 | files = [ 96 | {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, 97 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, 98 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, 99 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, 100 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, 101 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, 102 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, 103 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, 104 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, 105 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, 106 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, 107 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, 108 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, 109 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, 110 | {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, 111 | {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, 112 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, 113 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, 114 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, 115 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, 116 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, 117 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, 118 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, 119 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, 120 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, 121 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, 122 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, 123 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, 124 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, 125 | {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, 126 | {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, 127 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, 128 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, 129 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, 130 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, 131 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, 132 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, 133 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, 134 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, 135 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, 136 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, 137 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, 138 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, 139 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, 140 | {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, 141 | {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, 142 | {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, 143 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, 144 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, 145 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, 146 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, 147 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, 148 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, 149 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, 150 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, 151 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, 152 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, 153 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, 154 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, 155 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, 156 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, 157 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, 158 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, 159 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, 160 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, 161 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, 162 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, 163 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, 164 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, 165 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, 166 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, 167 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, 168 | {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, 169 | {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, 170 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, 171 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, 172 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, 173 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, 174 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, 175 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, 176 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, 177 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, 178 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, 179 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, 180 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, 181 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, 182 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, 183 | {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, 184 | {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, 185 | {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, 186 | ] 187 | 188 | [[package]] 189 | name = "idna" 190 | version = "3.7" 191 | description = "Internationalized Domain Names in Applications (IDNA)" 192 | optional = false 193 | python-versions = ">=3.5" 194 | files = [ 195 | {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, 196 | {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, 197 | ] 198 | 199 | [[package]] 200 | name = "mnemonic" 201 | version = "0.20" 202 | description = "Implementation of Bitcoin BIP-0039" 203 | optional = false 204 | python-versions = ">=3.5" 205 | files = [ 206 | {file = "mnemonic-0.20-py3-none-any.whl", hash = "sha256:acd2168872d0379e7a10873bb3e12bf6c91b35de758135c4fbd1015ef18fafc5"}, 207 | {file = "mnemonic-0.20.tar.gz", hash = "sha256:7c6fb5639d779388027a77944680aee4870f0fcd09b1e42a5525ee2ce4c625f6"}, 208 | ] 209 | 210 | [[package]] 211 | name = "pycparser" 212 | version = "2.22" 213 | description = "C parser in Python" 214 | optional = false 215 | python-versions = ">=3.8" 216 | files = [ 217 | {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, 218 | {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, 219 | ] 220 | 221 | [[package]] 222 | name = "pydantic" 223 | version = "2.7.2" 224 | description = "Data validation using Python type hints" 225 | optional = false 226 | python-versions = ">=3.8" 227 | files = [ 228 | {file = "pydantic-2.7.2-py3-none-any.whl", hash = "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7"}, 229 | {file = "pydantic-2.7.2.tar.gz", hash = "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7"}, 230 | ] 231 | 232 | [package.dependencies] 233 | annotated-types = ">=0.4.0" 234 | pydantic-core = "2.18.3" 235 | typing-extensions = ">=4.6.1" 236 | 237 | [package.extras] 238 | email = ["email-validator (>=2.0.0)"] 239 | 240 | [[package]] 241 | name = "pydantic-core" 242 | version = "2.18.3" 243 | description = "Core functionality for Pydantic validation and serialization" 244 | optional = false 245 | python-versions = ">=3.8" 246 | files = [ 247 | {file = "pydantic_core-2.18.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c"}, 248 | {file = "pydantic_core-2.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7"}, 249 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c"}, 250 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2"}, 251 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34"}, 252 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a"}, 253 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b"}, 254 | {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6"}, 255 | {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426"}, 256 | {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812"}, 257 | {file = "pydantic_core-2.18.3-cp310-none-win32.whl", hash = "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779"}, 258 | {file = "pydantic_core-2.18.3-cp310-none-win_amd64.whl", hash = "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0"}, 259 | {file = "pydantic_core-2.18.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab"}, 260 | {file = "pydantic_core-2.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2"}, 261 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb"}, 262 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231"}, 263 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be"}, 264 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd"}, 265 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106"}, 266 | {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4"}, 267 | {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe"}, 268 | {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d"}, 269 | {file = "pydantic_core-2.18.3-cp311-none-win32.whl", hash = "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7"}, 270 | {file = "pydantic_core-2.18.3-cp311-none-win_amd64.whl", hash = "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7"}, 271 | {file = "pydantic_core-2.18.3-cp311-none-win_arm64.whl", hash = "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4"}, 272 | {file = "pydantic_core-2.18.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f"}, 273 | {file = "pydantic_core-2.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9"}, 274 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c"}, 275 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7"}, 276 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048"}, 277 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326"}, 278 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4"}, 279 | {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022"}, 280 | {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd"}, 281 | {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be"}, 282 | {file = "pydantic_core-2.18.3-cp312-none-win32.whl", hash = "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5"}, 283 | {file = "pydantic_core-2.18.3-cp312-none-win_amd64.whl", hash = "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6"}, 284 | {file = "pydantic_core-2.18.3-cp312-none-win_arm64.whl", hash = "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417"}, 285 | {file = "pydantic_core-2.18.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:eecf63195be644b0396f972c82598cd15693550f0ff236dcf7ab92e2eb6d3522"}, 286 | {file = "pydantic_core-2.18.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c44efdd3b6125419c28821590d7ec891c9cb0dff33a7a78d9d5c8b6f66b9702"}, 287 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e59fca51ffbdd1638b3856779342ed69bcecb8484c1d4b8bdb237d0eb5a45e2"}, 288 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70cf099197d6b98953468461d753563b28e73cf1eade2ffe069675d2657ed1d5"}, 289 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63081a49dddc6124754b32a3774331467bfc3d2bd5ff8f10df36a95602560361"}, 290 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:370059b7883485c9edb9655355ff46d912f4b03b009d929220d9294c7fd9fd60"}, 291 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a64faeedfd8254f05f5cf6fc755023a7e1606af3959cfc1a9285744cc711044"}, 292 | {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19d2e725de0f90d8671f89e420d36c3dd97639b98145e42fcc0e1f6d492a46dc"}, 293 | {file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:67bc078025d70ec5aefe6200ef094576c9d86bd36982df1301c758a9fff7d7f4"}, 294 | {file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf952c3f4100e203cbaf8e0c907c835d3e28f9041474e52b651761dc248a3c0"}, 295 | {file = "pydantic_core-2.18.3-cp38-none-win32.whl", hash = "sha256:9a46795b1f3beb167eaee91736d5d17ac3a994bf2215a996aed825a45f897558"}, 296 | {file = "pydantic_core-2.18.3-cp38-none-win_amd64.whl", hash = "sha256:200ad4e3133cb99ed82342a101a5abf3d924722e71cd581cc113fe828f727fbc"}, 297 | {file = "pydantic_core-2.18.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:304378b7bf92206036c8ddd83a2ba7b7d1a5b425acafff637172a3aa72ad7083"}, 298 | {file = "pydantic_core-2.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c826870b277143e701c9ccf34ebc33ddb4d072612683a044e7cce2d52f6c3fef"}, 299 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e201935d282707394f3668380e41ccf25b5794d1b131cdd96b07f615a33ca4b1"}, 300 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5560dda746c44b48bf82b3d191d74fe8efc5686a9ef18e69bdabccbbb9ad9442"}, 301 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b32c2a1f8032570842257e4c19288eba9a2bba4712af542327de9a1204faff8"}, 302 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:929c24e9dea3990bc8bcd27c5f2d3916c0c86f5511d2caa69e0d5290115344a9"}, 303 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a8376fef60790152564b0eab376b3e23dd6e54f29d84aad46f7b264ecca943"}, 304 | {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dccf3ef1400390ddd1fb55bf0632209d39140552d068ee5ac45553b556780e06"}, 305 | {file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41dbdcb0c7252b58fa931fec47937edb422c9cb22528f41cb8963665c372caf6"}, 306 | {file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:666e45cf071669fde468886654742fa10b0e74cd0fa0430a46ba6056b24fb0af"}, 307 | {file = "pydantic_core-2.18.3-cp39-none-win32.whl", hash = "sha256:f9c08cabff68704a1b4667d33f534d544b8a07b8e5d039c37067fceb18789e78"}, 308 | {file = "pydantic_core-2.18.3-cp39-none-win_amd64.whl", hash = "sha256:4afa5f5973e8572b5c0dcb4e2d4fda7890e7cd63329bd5cc3263a25c92ef0026"}, 309 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9"}, 310 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059"}, 311 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c"}, 312 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb"}, 313 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9"}, 314 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5"}, 315 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb"}, 316 | {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d"}, 317 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a"}, 318 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c"}, 319 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c"}, 320 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b"}, 321 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3"}, 322 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94"}, 323 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1"}, 324 | {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a"}, 325 | {file = "pydantic_core-2.18.3.tar.gz", hash = "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39"}, 326 | ] 327 | 328 | [package.dependencies] 329 | typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" 330 | 331 | [[package]] 332 | name = "pynacl" 333 | version = "1.5.0" 334 | description = "Python binding to the Networking and Cryptography (NaCl) library" 335 | optional = false 336 | python-versions = ">=3.6" 337 | files = [ 338 | {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, 339 | {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, 340 | {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, 341 | {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, 342 | {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, 343 | {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, 344 | {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, 345 | {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, 346 | {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, 347 | {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, 348 | ] 349 | 350 | [package.dependencies] 351 | cffi = ">=1.4.1" 352 | 353 | [package.extras] 354 | docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] 355 | tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] 356 | 357 | [[package]] 358 | name = "requests" 359 | version = "2.32.3" 360 | description = "Python HTTP for Humans." 361 | optional = false 362 | python-versions = ">=3.8" 363 | files = [ 364 | {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, 365 | {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, 366 | ] 367 | 368 | [package.dependencies] 369 | certifi = ">=2017.4.17" 370 | charset-normalizer = ">=2,<4" 371 | idna = ">=2.5,<4" 372 | urllib3 = ">=1.21.1,<3" 373 | 374 | [package.extras] 375 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 376 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 377 | 378 | [[package]] 379 | name = "requests-sse" 380 | version = "0.3.2" 381 | description = "server-sent events python client library based on requests" 382 | optional = false 383 | python-versions = "<4.0,>=3.7" 384 | files = [ 385 | {file = "requests_sse-0.3.2-py3-none-any.whl", hash = "sha256:c3399b689f6e7bf0eac7c2031211d66ffbb3ab77afc6c9226a71c73c06609f61"}, 386 | {file = "requests_sse-0.3.2.tar.gz", hash = "sha256:3e17bd324e500c9b11c7c23dd00af3f0222070328134bda67a8917985cfc4127"}, 387 | ] 388 | 389 | [package.dependencies] 390 | requests = ">=2.31.0,<3.0.0" 391 | 392 | [[package]] 393 | name = "stellar-sdk" 394 | version = "10.0.0" 395 | description = "The Python Stellar SDK library provides APIs to build transactions and connect to Horizon and Soroban-RPC server." 396 | optional = false 397 | python-versions = "<4.0,>=3.8" 398 | files = [ 399 | {file = "stellar_sdk-10.0.0-py3-none-any.whl", hash = "sha256:22b9e0f119850932c60f28c6c869b39966d24d4f633d50c55568b56193394226"}, 400 | {file = "stellar_sdk-10.0.0.tar.gz", hash = "sha256:e1ee4b27bb9230629f40fa106089cd05cddfcfe4586e687fa31e2c4b09d26e3a"}, 401 | ] 402 | 403 | [package.dependencies] 404 | mnemonic = ">=0.20,<0.21" 405 | pydantic = ">=2.5.2,<3.0.0" 406 | PyNaCl = ">=1.4.0,<2.0.0" 407 | requests = ">=2.26.0,<3.0.0" 408 | requests-sse = ">=0.3.0,<0.4.0" 409 | toml = ">=0.10.2,<0.11.0" 410 | xdrlib3 = ">=0.1.1,<0.2.0" 411 | 412 | [package.extras] 413 | aiohttp = ["aiohttp (>=3.9.1,<4.0.0)", "aiohttp-sse-client (>=0.2.1,<0.3.0)"] 414 | 415 | [[package]] 416 | name = "toml" 417 | version = "0.10.2" 418 | description = "Python Library for Tom's Obvious, Minimal Language" 419 | optional = false 420 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 421 | files = [ 422 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 423 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 424 | ] 425 | 426 | [[package]] 427 | name = "typing-extensions" 428 | version = "4.12.0" 429 | description = "Backported and Experimental Type Hints for Python 3.8+" 430 | optional = false 431 | python-versions = ">=3.8" 432 | files = [ 433 | {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, 434 | {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, 435 | ] 436 | 437 | [[package]] 438 | name = "urllib3" 439 | version = "2.2.1" 440 | description = "HTTP library with thread-safe connection pooling, file post, and more." 441 | optional = false 442 | python-versions = ">=3.8" 443 | files = [ 444 | {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, 445 | {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, 446 | ] 447 | 448 | [package.extras] 449 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] 450 | h2 = ["h2 (>=4,<5)"] 451 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 452 | zstd = ["zstandard (>=0.18.0)"] 453 | 454 | [[package]] 455 | name = "xdrlib3" 456 | version = "0.1.1" 457 | description = "A forked version of `xdrlib`, a module for encoding and decoding XDR (External Data Representation) data in Python." 458 | optional = false 459 | python-versions = ">=3.7,<4.0" 460 | files = [ 461 | {file = "xdrlib3-0.1.1-py3-none-any.whl", hash = "sha256:175c0645f347c64e76bb374c2109480007eb2ff04ad08acfe885a130d2b0877d"}, 462 | {file = "xdrlib3-0.1.1.tar.gz", hash = "sha256:26697013af45afab6c6ff9a598fd04979cde83fa7215da059551b088aea88f34"}, 463 | ] 464 | 465 | [metadata] 466 | lock-version = "2.0" 467 | python-versions = "^3.12" 468 | content-hash = "3de0b5633234d2695489e466b3442af770073d42b7e0f63047f926b5ca491197" 469 | -------------------------------------------------------------------------------- /aula02/sdk/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "stellar-bootcamp" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Lucas Oliveira "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.12" 10 | stellar-sdk = "^10.0.0" 11 | requests = "^2.32.3" 12 | 13 | 14 | [build-system] 15 | requires = ["poetry-core"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /aula02/sdk/token/main.py: -------------------------------------------------------------------------------- 1 | from wallet import create_alice_wallet, create_bob_wallet 2 | from utils import create_account, get_faucet 3 | from tokens import create_token, balance_of_token 4 | from stellar_sdk import Server 5 | 6 | print("✅ # Start creating a custom token on Stellar") 7 | 8 | print("✅ # Configure the server for the Standalone network (local)") 9 | server = Server("http://localhost:8000") 10 | 11 | # Criar carteiras para emissor e distribuidor 12 | issuer = create_alice_wallet() 13 | print(f"✅ # Issuer public key: {issuer.public_key}") 14 | 15 | distributor = create_bob_wallet() 16 | print(f"✅ # Distributor public key: {distributor.public_key}") 17 | 18 | # Depositar fundos na conta do emissor e do distribuidor 19 | get_faucet(issuer.public_key, server) 20 | # get_faucet(distributor.public_key, server) 21 | 22 | # Criar conta no Ledger para distribuidor 23 | starting_balance = 1000 24 | create_account(issuer, distributor.public_key, starting_balance, server) 25 | 26 | # Criar token personalizado 27 | ASSET_CODE = "NEARX" 28 | AMOUNT = 1_000_000 29 | 30 | token = create_token(issuer, distributor, ASSET_CODE, AMOUNT, server) 31 | 32 | 33 | balance_of_token(issuer, server) 34 | balance_of_token(distributor, server) 35 | 36 | 37 | print("✅ # Done!") 38 | -------------------------------------------------------------------------------- /aula02/sdk/token/tokens.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Asset, Network, TransactionBuilder 2 | from utils import get_transaction_by_hash 3 | 4 | 5 | def create_trust_line(issuer_wallet, distributor_wallet, asset_code, amount, server): 6 | print("✅ # Set the base fee") 7 | try: 8 | fee = server.fetch_base_fee() 9 | except Exception as e: 10 | print(f"Failed to fetch base fee: {e}") 11 | fee = 100 12 | 13 | token = Asset(asset_code, issuer_wallet.public_key) 14 | distributor_account = server.load_account(distributor_wallet.public_key) 15 | 16 | print("✅ # Build transaction") 17 | transaction = ( 18 | TransactionBuilder( 19 | source_account=distributor_account, 20 | network_passphrase=Network.STANDALONE_NETWORK_PASSPHRASE, 21 | base_fee=fee, 22 | ) 23 | .add_text_memo("Create a trustline") 24 | .append_change_trust_op(token, amount) 25 | .set_timeout(30) 26 | .build() 27 | ) 28 | 29 | print("✅ # Sign the transaction with Sender's secret key") 30 | transaction.sign(distributor_wallet.secret) 31 | 32 | print("✅ # Submits the transaction to the Horizon server") 33 | response = server.submit_transaction(transaction) 34 | 35 | tx_hash = response["hash"] 36 | print(f"✅ # Transaction Hash: {tx_hash}") 37 | 38 | if response["successful"]: 39 | print("✅ # Trustline created successful") 40 | else: 41 | raise Exception("Transaction was failed") 42 | 43 | get_transaction_by_hash(server, tx_hash) 44 | return token 45 | 46 | 47 | def destribution_tokens(issuer_wallet, distributor_wallet, token, amount, server): 48 | print("✅ # Set the base fee") 49 | try: 50 | fee = server.fetch_base_fee() 51 | except Exception as e: 52 | print(f"Failed to fetch base fee: {e}") 53 | fee = 100 54 | 55 | issuer_account = server.load_account(issuer_wallet.public_key) 56 | 57 | print("✅ # Build transaction") 58 | transaction = ( 59 | TransactionBuilder( 60 | source_account=issuer_account, 61 | network_passphrase=Network.STANDALONE_NETWORK_PASSPHRASE, 62 | base_fee=fee, 63 | ) 64 | .add_text_memo(f"Token distribution {token.code}") 65 | .append_payment_op(distributor_wallet.public_key, token, amount) 66 | .set_timeout(30) 67 | .build() 68 | ) 69 | 70 | print("✅ # Sign the transaction with Sender's secret key") 71 | transaction.sign(issuer_wallet.secret) 72 | 73 | print("✅ # Submits the transaction to the Horizon server") 74 | response = server.submit_transaction(transaction) 75 | 76 | tx_hash = response["hash"] 77 | print(f"✅ # Transaction Hash: {tx_hash}") 78 | 79 | if response["successful"]: 80 | print("✅ # Distribuition successful") 81 | else: 82 | raise Exception("Transaction was failed") 83 | 84 | get_transaction_by_hash(server, tx_hash) 85 | 86 | 87 | def create_token(issuer_wallet, distributor_wallet, asset_code, amount, server): 88 | 89 | token = create_trust_line( 90 | issuer_wallet, distributor_wallet, asset_code, amount, server 91 | ) 92 | destribution_tokens(issuer_wallet, distributor_wallet, token, amount, server) 93 | 94 | return token 95 | 96 | 97 | def balance_of_token(wallet, server): 98 | account = server.accounts().account_id(wallet.public_key).call() 99 | balances = account["balances"] 100 | for balance in balances: 101 | asset_type = ( 102 | balance["asset_code"] 103 | if balance.get("asset_code", False) 104 | else balance["asset_type"] 105 | ) 106 | balance_amount = balance["balance"] 107 | print(f"✅ # Balances for account {wallet.public_key}:", end=" ") 108 | print(f"Asset Type: {asset_type}, Balance: {balance_amount}") 109 | -------------------------------------------------------------------------------- /aula02/sdk/token/utils.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Asset, Network, TransactionBuilder 2 | from stellar_sdk.exceptions import NotFoundError 3 | from requests import get, RequestException 4 | 5 | 6 | def soft_create_account(public_key): 7 | url = "http://localhost:8000/friendbot" 8 | params = {"addr": public_key} 9 | timeout = 30 10 | try: 11 | r = get(url, params=params, timeout=timeout) 12 | r.raise_for_status() 13 | except RequestException as e: 14 | raise ValueError(f"Error in get faucet: {str(e)}") from e 15 | 16 | 17 | def validate_wallet(public_key, server): 18 | try: 19 | server.load_account(public_key) 20 | except NotFoundError: 21 | print("The destination account does not exist!") 22 | print("Creating Account!") 23 | soft_create_account(public_key) 24 | 25 | 26 | def validate_wallet_balance(public_key, server): 27 | try: 28 | r = server.accounts().account_id(public_key).call() 29 | except Exception as e: 30 | raise Exception(f"Error in getting account data: {str(e)}") from e 31 | 32 | for balance in r["balances"]: 33 | if balance["asset_type"] == "native": 34 | return float(balance["balance"]) > 0 35 | 36 | 37 | def check_balances(server, public_key): 38 | account = server.accounts().account_id(public_key).call() 39 | balances = account["balances"] 40 | print(f"✅ # Balances for account {public_key}:", end=": ") 41 | for balance in balances: 42 | asset_type = balance["asset_type"] 43 | balance_amount = balance["balance"] 44 | print(f"Asset Type: {asset_type}, Balance: {balance_amount}") 45 | 46 | 47 | def get_faucet(public_key, server): 48 | print(f"✅ # Try deposit 10.000XML to {public_key}") 49 | 50 | validate_wallet(public_key, server) 51 | if validate_wallet_balance(public_key, server): 52 | print(f"Wallet: {public_key} already balance!") 53 | return 54 | 55 | print(f"Wallet: {public_key} need a deposit!") 56 | 57 | soft_create_account(public_key) 58 | 59 | 60 | def create_account(funder_wallet, new_account_public_key, starting_balance, server): 61 | funder_account = server.load_account(funder_wallet.public_key) 62 | 63 | print("✅ # Set the base fee") 64 | try: 65 | fee = server.fetch_base_fee() 66 | except Exception as e: 67 | print(f"Failed to fetch base fee: {e}") 68 | fee = 100 69 | 70 | print("✅ # Build transaction") 71 | transaction = ( 72 | TransactionBuilder( 73 | source_account=funder_account, 74 | network_passphrase=Network.STANDALONE_NETWORK_PASSPHRASE, 75 | base_fee=fee, 76 | ) 77 | .append_create_account_op( 78 | destination=new_account_public_key, starting_balance=str(starting_balance) 79 | ) 80 | .append_payment_op(new_account_public_key, Asset.native(), "10.25") 81 | .set_timeout(30) 82 | .build() 83 | ) 84 | 85 | print("✅ # Sign the transaction with Sender's secret key") 86 | transaction.sign(funder_wallet.secret) 87 | 88 | print("✅ # Submits the transaction to the Horizon server") 89 | response = server.submit_transaction(transaction) 90 | 91 | tx_hash = response["hash"] 92 | print(f"✅ # Transaction Hash: {tx_hash}") 93 | 94 | if response["successful"]: 95 | print("✅ # Create account successful") 96 | else: 97 | raise Exception("Transaction was failed to be created") 98 | 99 | return response 100 | 101 | def get_transaction_by_hash(server, transaction_hash): 102 | transaction = server.transactions().transaction(transaction_hash).call() 103 | print("✅ # Transaction details:") 104 | print(f" - ID: {transaction['id']}") 105 | print(f" - Hash: {transaction['hash']}") 106 | print(f" - Ledger: {transaction['ledger']}") 107 | print(f" - Created At: {transaction['created_at']}") 108 | print(f" - Source Account: {transaction['source_account']}") 109 | print(f" - Memo: {transaction['memo']}") 110 | print(f" - Fee Charged: {transaction['fee_charged']}") 111 | print(f" - Operation Count: {transaction['operation_count']}") 112 | print(f" - Successful: {transaction['successful']}") 113 | 114 | return transaction -------------------------------------------------------------------------------- /aula02/sdk/token/wallet.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Keypair 2 | 3 | 4 | def create_alice_wallet(): 5 | print("✅ # Alice's wallet created (ISSUER)") 6 | alice_secret_key = "SAKKTW5AEJO7Y5DOGUKINE6NF55CR37OWK3WIX4JWQ7LHOOUIH2VQYR4" 7 | alice = Keypair.from_secret(alice_secret_key) 8 | assert alice.public_key == "GBTIDN5UQ3P4HT3CSIEYU55F6INXOMYOTU6U5KM67QMXPPUCTABT35U5" 9 | 10 | return alice 11 | 12 | 13 | def create_bob_wallet(): 14 | print("✅ # Bob's wallet created (DISTRIBUTOR)") 15 | bob_secret_key = "SCHBR3CYVBCN4DKDML5VKMAP3Q7B7XN6ARI34UHCOEBHLMNXEUTGIXI5" 16 | bob = Keypair.from_secret(bob_secret_key) 17 | assert bob.public_key == "GCGRVQLR2BKLNP3XP3N2R47Z52X2OIBC7QVZUI4LAZYXRRVIN5TP5GVJ" 18 | 19 | return bob 20 | -------------------------------------------------------------------------------- /aula02/setup-node/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | stellar: 5 | image: stellar/quickstart:testing 6 | ports: 7 | - "8000:8000" 8 | - "6061:6061" 9 | command: [ 10 | "--local", 11 | "--enable-soroban-rpc", 12 | "--enable-soroban-rpc-admin-endpoint" 13 | ] 14 | 15 | prometheus: 16 | image: prom/prometheus 17 | volumes: 18 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 19 | ports: 20 | - "9090:9090" 21 | depends_on: 22 | - stellar 23 | 24 | grafana: 25 | image: grafana/grafana 26 | ports: 27 | - "3000:3000" 28 | depends_on: 29 | - prometheus 30 | -------------------------------------------------------------------------------- /aula02/setup-node/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: 'stellar_node' 6 | static_configs: 7 | - targets: ['stellar:6061'] -------------------------------------------------------------------------------- /aula02/setup-node/stellar_dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROMETHEUS", 5 | "label": "prometheus", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__elements": {}, 13 | "__requires": [ 14 | { 15 | "type": "panel", 16 | "id": "gauge", 17 | "name": "Gauge", 18 | "version": "" 19 | }, 20 | { 21 | "type": "grafana", 22 | "id": "grafana", 23 | "name": "Grafana", 24 | "version": "11.0.0" 25 | }, 26 | { 27 | "type": "datasource", 28 | "id": "prometheus", 29 | "name": "Prometheus", 30 | "version": "1.0.0" 31 | }, 32 | { 33 | "type": "panel", 34 | "id": "stat", 35 | "name": "Stat", 36 | "version": "" 37 | } 38 | ], 39 | "annotations": { 40 | "list": [ 41 | { 42 | "builtIn": 1, 43 | "datasource": { 44 | "type": "grafana", 45 | "uid": "-- Grafana --" 46 | }, 47 | "enable": true, 48 | "hide": true, 49 | "iconColor": "rgba(0, 211, 255, 1)", 50 | "name": "Annotations & Alerts", 51 | "type": "dashboard" 52 | } 53 | ] 54 | }, 55 | "editable": true, 56 | "fiscalYearStartMonth": 0, 57 | "graphTooltip": 0, 58 | "id": null, 59 | "links": [], 60 | "panels": [ 61 | { 62 | "datasource": { 63 | "type": "prometheus", 64 | "uid": "${DS_PROMETHEUS}" 65 | }, 66 | "fieldConfig": { 67 | "defaults": { 68 | "color": { 69 | "mode": "thresholds" 70 | }, 71 | "mappings": [], 72 | "thresholds": { 73 | "mode": "absolute", 74 | "steps": [ 75 | { 76 | "color": "green", 77 | "value": null 78 | } 79 | ] 80 | } 81 | }, 82 | "overrides": [] 83 | }, 84 | "gridPos": { 85 | "h": 8, 86 | "w": 12, 87 | "x": 0, 88 | "y": 0 89 | }, 90 | "id": 2, 91 | "options": { 92 | "colorMode": "value", 93 | "graphMode": "area", 94 | "justifyMode": "auto", 95 | "orientation": "auto", 96 | "reduceOptions": { 97 | "calcs": [ 98 | "lastNotNull" 99 | ], 100 | "fields": "", 101 | "values": false 102 | }, 103 | "showPercentChange": false, 104 | "textMode": "auto", 105 | "wideLayout": true 106 | }, 107 | "pluginVersion": "11.0.0", 108 | "targets": [ 109 | { 110 | "datasource": { 111 | "type": "prometheus", 112 | "uid": "${DS_PROMETHEUS}" 113 | }, 114 | "disableTextWrap": false, 115 | "editorMode": "builder", 116 | "expr": "soroban_rpc_transactions_count_sum", 117 | "fullMetaSearch": false, 118 | "includeNullMetadata": true, 119 | "instant": false, 120 | "legendFormat": "__auto", 121 | "range": true, 122 | "refId": "A", 123 | "useBackend": false 124 | } 125 | ], 126 | "title": "Total Tx ", 127 | "type": "stat" 128 | }, 129 | { 130 | "datasource": { 131 | "type": "prometheus", 132 | "uid": "${DS_PROMETHEUS}" 133 | }, 134 | "fieldConfig": { 135 | "defaults": { 136 | "color": { 137 | "mode": "thresholds" 138 | }, 139 | "mappings": [], 140 | "thresholds": { 141 | "mode": "absolute", 142 | "steps": [ 143 | { 144 | "color": "green", 145 | "value": null 146 | } 147 | ] 148 | } 149 | }, 150 | "overrides": [] 151 | }, 152 | "gridPos": { 153 | "h": 8, 154 | "w": 12, 155 | "x": 12, 156 | "y": 0 157 | }, 158 | "id": 1, 159 | "options": { 160 | "minVizHeight": 75, 161 | "minVizWidth": 75, 162 | "orientation": "auto", 163 | "reduceOptions": { 164 | "calcs": [ 165 | "lastNotNull" 166 | ], 167 | "fields": "", 168 | "values": false 169 | }, 170 | "showThresholdLabels": false, 171 | "showThresholdMarkers": true, 172 | "sizing": "auto" 173 | }, 174 | "pluginVersion": "11.0.0", 175 | "targets": [ 176 | { 177 | "datasource": { 178 | "type": "prometheus", 179 | "uid": "${DS_PROMETHEUS}" 180 | }, 181 | "disableTextWrap": false, 182 | "editorMode": "builder", 183 | "expr": "soroban_rpc_ingest_local_latest_ledger", 184 | "fullMetaSearch": false, 185 | "includeNullMetadata": true, 186 | "instant": false, 187 | "legendFormat": "__auto", 188 | "range": true, 189 | "refId": "A", 190 | "useBackend": false 191 | } 192 | ], 193 | "title": "Current Blocos (Ledger)", 194 | "type": "gauge" 195 | } 196 | ], 197 | "schemaVersion": 39, 198 | "tags": [], 199 | "templating": { 200 | "list": [] 201 | }, 202 | "time": { 203 | "from": "now-6h", 204 | "to": "now" 205 | }, 206 | "timeRangeUpdatedDuringEditOrView": false, 207 | "timepicker": {}, 208 | "timezone": "browser", 209 | "title": "Stellar Quickstart Node", 210 | "uid": "ddnbm5gpcwkjkd", 211 | "version": 1, 212 | "weekStart": "" 213 | } -------------------------------------------------------------------------------- /aula03/.soroban/contract-ids/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula03/.soroban/contract-ids/.gitkeep -------------------------------------------------------------------------------- /aula03/.soroban/network/home.toml: -------------------------------------------------------------------------------- 1 | rpc_url = "http://localhost:8000/soroban/rpc" 2 | network_passphrase = "Standalone Network ; February 2017" 3 | -------------------------------------------------------------------------------- /aula03/README.md: -------------------------------------------------------------------------------- 1 | # Introdução ao Rust 2 | 3 | ## 1. Filosofia do Rust 4 | 5 | - Segurança e Performance 6 | - Concorrência 7 | 8 | ## 2. Ecossistema Rust 9 | 10 | **Ferramentas Principais** 11 | 12 | - Rustup: Ferramenta de linha de comando para gerenciar instalações de Rust. Facilita a instalação e atualização do Rust, bem como a alternância entre diferentes versões de Rust. 13 | - rustc: O compilador de Rust. Compila o código fonte em binários executáveis, garantindo que o código esteja livre de erros de memória comuns. 14 | 15 | **Gestão de Projetos e Dependências** 16 | 17 | - Cargo: Sistema de construção e gerenciador de pacotes de Rust. Simplifica a criação, compilação e gerenciamento de dependências em projetos Rust. 18 | 19 | - Cargo.toml: Arquivo de configuração usado pelo Cargo para especificar as dependências do projeto, configurações de compilação e metadados do projeto. Centraliza todas as informações do projeto em um único lugar. 20 | 21 | - Crates: Pacotes de bibliotecas ou programas Rust que podem ser compartilhados e reutilizados. Promove a reutilização de código e a modularidade, permitindo que os desenvolvedores aproveitem bibliotecas de terceiros. 22 | 23 | **Processo de Compilação** 24 | 25 | - Etapas do Processo: 26 | 27 | ## 3. Comparação com Outros Ecossistemas (Python e JavaScript) 28 | 29 | **Prós do Rust** 30 | 31 | - Segurança de Memória: Graças ao sistema de propriedade do Rust. 32 | - Performance: Comparable a C/C++. 33 | - Concorrência: Seguro e eficiente devido ao modelo de concorrência do Rust. 34 | 35 | **Contras do Rust** 36 | 37 | - Curva de Aprendizado: Mais íngreme comparado a Python e JavaScript. 38 | - Ecosistema: Menos maduro em algumas áreas específicas comparado a Python (ex. Data Science) e JavaScript (ex. Desenvolvimento Web). 39 | 40 | **Comparação Prática** 41 | 42 | **Python:** - Pros: Facilidade de uso, vasta biblioteca padrão, excelente para prototipagem e desenvolvimento rápido. - Contras: Performance inferior, não tão seguro em termos de memória. 43 | **JavaScript:** 44 | 45 | - Pros: Dominância no desenvolvimento web, enorme ecossistema e comunidade. 46 | - Contras: Problemas de segurança, inconsistências e peculiaridades da linguagem. 47 | 48 | **Exemplo de Aplicações Típicas** 49 | 50 | - Rust: Sistemas embarcados, software de sistema, blockchain, aplicações de alta performance. 51 | - Python: Ciência de dados, aprendizado de máquina, automação de tarefas, desenvolvimento web (Django, Flask). 52 | - JavaScript: Aplicações web front-end e back-end (Node.js), desenvolvimento de aplicativos móveis (React Native). 53 | 54 | ## 4. Recursos e Comunidade 55 | 56 | **Livros e Tutoriais:** 57 | 58 | - [NearX](https://www.nearx.com.br) 59 | - ["The Rust Programming Language" (também conhecido como "The Book")](https://doc.rust-lang.org/book/index.html). 60 | - [Comprehensive Rust 🦀](https://google.github.io/comprehensive-rust/bare-metal.html) 61 | - [Rustlings](https://rustlings.cool). 62 | - [Rust by Examples](https://doc.rust-lang.org/rust-by-example/index.html). 63 | 64 | **Comunidade:** 65 | 66 | - [Discord](https://discord.com/invite/rust-lang). 67 | - [Fórum](https://users.rust-lang.org). 68 | 69 | ## 2 Criando um projeto com cargo 70 | 71 | ```bash 72 | cargo new learn 73 | ``` 74 | 75 | ## 2.1 Básico de Rust 76 | 77 | - variaveis 78 | - tipos 79 | - if, else 80 | - for, while, loop 81 | - fn 82 | - struct, enum, impl, trait 83 | 84 | ## 3. Smartcontract Hello World 85 | 86 | ## 3.1 Instalando o Soroban e Wasm target 87 | 88 | ```bash 89 | rustup target add wasm32-unknown-unknown 90 | ``` 91 | 92 | ```bash 93 | cargo install --locked soroban-cli --version 21.0.0-rc.1 94 | ``` 95 | 96 | ## 3.2 Configurar o client (Soroban) 97 | 98 | ```bash 99 | soroban network add local \ 100 | --global \ 101 | --rpc-url "http://localhost:8000/soroban/rpc" \ 102 | --network-passphrase "Standalone Network ; February 2017" 103 | ``` 104 | 105 | ## 3.3 Criando uma wallet com Soroban 106 | 107 | ``` 108 | soroban keys generate --global bob --network local 109 | ``` 110 | 111 | ## 3.4 Criando projeto 112 | 113 | ```bash 114 | soroban contract init soroban-smartcontracts 115 | ``` 116 | 117 | ## 3.4 Fazendo build do contrato 118 | 119 | ```bash 120 | soroban contract build 121 | ``` 122 | 123 | ```bash 124 | cargo build --target wasm32-unknown-unknown --release 125 | ``` 126 | 127 | ## 3.5 Testando o contrato 128 | 129 | ```bash 130 | cargo test 131 | ``` 132 | 133 | ## 3.6 Deployando o contrato 134 | 135 | ```bash 136 | soroban contract deploy \ 137 | --wasm target/wasm32-unknown-unknown/release/hello_world.wasm \ 138 | --source bob \ 139 | --network local 140 | ``` 141 | 142 | ## 3.7 Interagindo com o contrato 143 | 144 | ```bash 145 | soroban contract invoke \ 146 | --id \ 147 | --source bob \ 148 | --network local \ 149 | -- \ 150 | hello \ 151 | --to Lucas 152 | ``` -------------------------------------------------------------------------------- /aula03/learn/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "learn" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /aula03/learn/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "learn" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /aula03/learn/src/main.rs: -------------------------------------------------------------------------------- 1 | // [x] variaveis 2 | // [x] tipos 3 | // [x] if, else 4 | // [x] for, while, loop 5 | // [x] fn 6 | // [ ] struct, enum, generics, impl, trait 7 | 8 | use std::collections::HashMap; 9 | use std::fmt::{self, Display}; 10 | 11 | fn soma(x: u8, y: u8) -> u8 { 12 | x + y 13 | } 14 | 15 | fn main() { 16 | // let x1 = 90; 17 | // let x2 = 91; 18 | 19 | // let n = "string".to_string(); 20 | 21 | // { 22 | // // a' 23 | 24 | // let x90 = n; 25 | // } // a' 26 | 27 | // println!("{}", x90); 28 | 29 | // let x3 = soma(x1, x2); 30 | // println!("{}", x3); 31 | 32 | // println!("{}", x1); 33 | 34 | // // inteiro: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 35 | // // float: f32, f64 36 | // // String: &str 37 | // // bool: true, false 38 | // // char: "a" 39 | // // Vec 40 | // // Map 41 | 42 | // let my_name_bits: Vec = [76, 117, 99, 97, 115, 32, 22].to_vec(); 43 | // let mut alunos: HashMap = HashMap::new(); 44 | 45 | // let nome = "Lucas 👨‍💻"; 46 | // alunos.insert(1, nome.to_string()); 47 | 48 | // println!("Nome: {:?}", alunos); 49 | 50 | // let c = 10; 51 | 52 | // if c > 10 { 53 | // println!("sim"); 54 | // } else { 55 | // println!("nao") 56 | // } 57 | 58 | // for item in 0..=1 { 59 | // println!("{}", item); 60 | // } 61 | 62 | // for bit in &my_name_bits { 63 | // println!("{}", bit); 64 | // } 65 | 66 | // my_name_bits.iter().for_each(|x| println!("{}", x)); 67 | 68 | 69 | 70 | 71 | let lucas = Pessoa::new("Lucas".to_string(), 19); 72 | 73 | 74 | println!("{}", lucas); 75 | 76 | } 77 | 78 | /// # python 79 | /// 80 | /// ```python 81 | /// 82 | /// class Pessoa: 83 | /// def __init__(self, nome: str, idade: int): 84 | /// self.idade = idade 85 | /// self.nome = nome 86 | /// 87 | /// def niver(self): 88 | /// self.idade += 1 89 | /// ``` 90 | /// 91 | 92 | struct Pessoa { 93 | nome: String, 94 | idade: u8, 95 | } 96 | 97 | impl Pessoa { 98 | fn new(nome: String, idade: u8) -> Pessoa { 99 | Pessoa { 100 | nome, 101 | idade, 102 | } 103 | } 104 | } 105 | 106 | 107 | impl Display for Pessoa { 108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 109 | write!(f, "Pessoa(Nome: {}, Idade: {})", self.nome, self.idade) 110 | } 111 | } -------------------------------------------------------------------------------- /aula03/memory_manager/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "memory_manager" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /aula03/memory_manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memory_manager" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /aula03/memory_manager/src/main.rs: -------------------------------------------------------------------------------- 1 | //! # Gerenciamento de Memória em Rust 2 | //! **Estes exemplos demonstram conceitos de gerenciamento de memória em Rust incluindo:** 3 | //! 4 | //! - [Ownership e Borrowing](fn.main.html#1-ownership-e-borrowing) 5 | //! - [Lifetimes](fn.main.html#lifetimes) 6 | //! - [Smart Pointers](fn.main.html#smart-pointers) 7 | //! - [Borrow Checker](fn.main.html#borrow-checker) 8 | //! - [Zero-Cost Abstractions](fn.main.html#zero-cost-abstractions) 9 | 10 | /// ## 1. Ownership, Borrowing e Lifetimes 11 | /// 12 | /// ### Ownership 13 | /// 14 | /// - **Cada valor tem um proprietário único (Ownership)** 15 | /// 16 | /// Cada valor em Rust tem uma única variável que é seu proprietário. 17 | /// Quando o proprietário sai do escopo, o valor é desalocado automaticamente. 18 | /// Isso significa que não pode haver dois proprietários para o mesmo valor ao mesmo tempo, 19 | /// o que evita duplicações e ambiguidades sobre quem é responsável pela desalocação do valor. 20 | /// 21 | /// ```rust 22 | /// fn ownership_example() { 23 | /// let s1 = String::from("hello"); 24 | /// let s2 = s1; // s1 é movido para s2 25 | /// // println!("{}", s1); // Erro: s1 não é mais válido 26 | /// println!("{}", s2); 27 | /// } 28 | /// ``` 29 | /// 30 | /// ### Borrowing 31 | /// 32 | /// - **Pode haver um número ilimitado de referências imutáveis, ou apenas uma referência mutável** 33 | /// 34 | /// Rust permite emprestimos de valores para outras variáveis ou 35 | /// funções sem transferir a propriedade. Existem dois tipos de referências (empréstimos): 36 | /// 37 | /// - **Referências imutáveis (&T):** 38 | /// * Pode haver quantas referências imutáveis forem necessárias, 39 | /// desde que não haja referência mutável ao mesmo tempo. 40 | /// - **Referências mutáveis (&mut T):** 41 | /// * Só pode haver uma referência mutável de cada vez, 42 | /// e nenhuma referência imutável pode coexistir com ela. 43 | /// 44 | /// ```rust 45 | /// fn borrowing_example() { 46 | /// let s1 = String::from("hello"); 47 | /// let len = calculate_length(&s1); // s1 é emprestado para a função 48 | /// println!("The length of '{}' is {}.", s1, len); 49 | /// } 50 | /// 51 | /// fn calculate_length(s: &String) -> usize { 52 | /// s.len() 53 | /// } 54 | /// ``` 55 | /// 56 | /// ### Lifetimes 57 | /// 58 | /// - **As referências sempre devem ser válidas** 59 | /// 60 | /// Rust usa lifetimes para garantir que todas as referências sejam válidas enquanto estão em uso. 61 | /// Isso significa que o tempo de vida (lifetime) de uma referência não pode ultrapassar o 62 | /// tempo de vida do valor ao qual ela se refere. Lifetimes são anotados explicitamente 63 | /// pelo compilador ou pelo programador para garantir essa segurança. 64 | /// 65 | /// ```rust 66 | /// fn lifetimes_basic_example() { 67 | /// let r; 68 | /// { 69 | /// let x = 5; 70 | /// r = &x; // 'x' não vive o suficiente 71 | /// } 72 | /// // println!("r: {}", r); // Erro de compilação 73 | /// } 74 | /// ``` 75 | /// 76 | /// - **Cada valor tem um único proprietário:** 77 | /// * Quando o proprietário sai do escopo, o valor é desalocado. 78 | /// - **Pode haver múltiplas referências imutáveis ou uma única referência mutável:** 79 | /// * Não pode haver uma referência mutável e uma referência imutável ao mesmo tempo. 80 | /// - **As referências devem ser sempre válidas:** 81 | /// * O tempo de vida das referências não pode ultrapassar o tempo de vida dos valores aos quais se referem 82 | /// 83 | 84 | /// ## 3. Smart Pointers 85 | /// 86 | /// ### Box 87 | /// 88 | /// `Box` permite alocar memória no heap enquanto mantém um ponteiro no stack. 89 | /// É usado para dados grandes ou tipos cujo tamanho não é conhecido em tempo de compilação. 90 | /// 91 | /// ```rust 92 | /// fn box_example() { 93 | /// let b = Box::new(5); 94 | /// println!("b = {}", b); 95 | /// } 96 | /// ``` 97 | /// 98 | /// ### Rc e Arc 99 | /// 100 | /// `Rc` (Reference Counted) permite múltiplas referências imutáveis a um dado no heap, 101 | /// enquanto `Arc` (Atomic Reference Counted) permite isso em um contexto multi-thread, 102 | /// com contagem de referências segura para concorrência. 103 | /// 104 | /// ```rust 105 | /// use std::rc::Rc; 106 | /// 107 | /// fn rc_example() { 108 | /// let a = Rc::new(5); 109 | /// let b = Rc::clone(&a); 110 | /// println!("a = {}, b = {}", a, b); 111 | /// } 112 | /// ``` 113 | 114 | /// ## 4. Borrow Checker 115 | /// 116 | /// ### Mutabilidade 117 | /// 118 | /// Rust garante que apenas uma referência mutável ou múltiplas referências imutáveis estejam ativas ao mesmo tempo, 119 | /// prevenindo condições de corrida e outros problemas de concorrência. 120 | /// 121 | /// ```rust 122 | /// fn mutability_example() { 123 | /// let mut s = String::from("hello"); 124 | /// change(&mut s); 125 | /// println!("{}", s); 126 | /// } 127 | /// 128 | /// fn change(some_string: &mut String) { 129 | /// some_string.push_str(", world"); 130 | /// } 131 | /// ``` 132 | /// 133 | /// ### Split Borrows 134 | /// 135 | /// Rust não permite referências mutáveis enquanto existirem referências imutáveis, 136 | /// garantindo segurança em tempo de compilação. 137 | /// 138 | /// ```rust 139 | /// fn split_borrows_example() { 140 | /// let mut s = String::from("hello"); 141 | /// let r1 = &s; 142 | /// let r2 = &s; 143 | /// // let r3 = &mut s; // Erro de compilação 144 | /// println!("{} and {}", r1, r2); 145 | /// } 146 | /// ``` 147 | 148 | /// ## 5. Zero-Cost Abstractions 149 | /// 150 | /// ### Iteradores 151 | /// 152 | /// Iteradores em Rust são zero-cost abstractions, ou seja, são otimizados pelo compilador 153 | /// para não introduzir overhead adicional em tempo de execução. 154 | /// 155 | /// ```rust 156 | /// fn iterator_example() { 157 | /// let v = vec![1, 2, 3]; 158 | /// let v_iter = v.iter(); 159 | /// for val in v_iter { 160 | /// println!("{}", val); 161 | /// } 162 | /// } 163 | /// ``` 164 | /// 165 | /// ### Custom Iterator 166 | /// 167 | /// Implementar iteradores customizados em Rust permite criar abstrações poderosas sem comprometer a performance, 168 | /// beneficiando-se das otimizações do compilador. 169 | /// 170 | /// ```rust 171 | /// struct Counter { 172 | /// count: u32, 173 | /// } 174 | /// 175 | /// impl Counter { 176 | /// fn new() -> Counter { 177 | /// Counter { count: 0 } 178 | /// } 179 | /// } 180 | /// 181 | /// impl Iterator for Counter { 182 | /// type Item = u32; 183 | /// 184 | /// fn next(&mut self) -> Option { 185 | /// self.count += 1; 186 | /// if self.count < 6 { 187 | /// Some(self.count) 188 | /// } else { 189 | /// None 190 | /// } 191 | /// } 192 | /// } 193 | /// 194 | /// fn custom_iterator_example() { 195 | /// let counter = Counter::new(); 196 | /// for val in counter { 197 | /// println!("{}", val); 198 | /// } 199 | /// } 200 | /// ``` 201 | 202 | fn main() {} -------------------------------------------------------------------------------- /aula03/rustc/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula03/rustc/lib.rs -------------------------------------------------------------------------------- /aula03/rustc/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrxschool/stellar-bootcamp/df485547aafba5bd7a5d137f9cd9d75d41f48a46/aula03/rustc/main -------------------------------------------------------------------------------- /aula03/rustc/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/.gitignore: -------------------------------------------------------------------------------- 1 | # Rust's output directory 2 | target 3 | 4 | # Local Soroban settings 5 | .soroban 6 | -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "contracts/*", 5 | ] 6 | 7 | [workspace.dependencies] 8 | soroban-sdk = "20.3.2" 9 | 10 | [profile.release] 11 | opt-level = "z" 12 | overflow-checks = true 13 | debug = 0 14 | strip = "symbols" 15 | debug-assertions = false 16 | panic = "abort" 17 | codegen-units = 1 18 | lto = true 19 | 20 | # For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile 21 | [profile.release-with-logs] 22 | inherits = "release" 23 | debug-assertions = true 24 | -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/README.md: -------------------------------------------------------------------------------- 1 | # Soroban Project 2 | 3 | ## Project Structure 4 | 5 | This repository uses the recommended structure for a Soroban project: 6 | ```text 7 | . 8 | ├── contracts 9 | │   └── hello_world 10 | │   ├── src 11 | │   │   ├── lib.rs 12 | │   │   └── test.rs 13 | │   └── Cargo.toml 14 | ├── Cargo.toml 15 | └── README.md 16 | ``` 17 | 18 | - New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. 19 | - If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. 20 | - Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. 21 | - Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/contracts/hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-world" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | doctest = false 10 | 11 | [dependencies] 12 | soroban-sdk = { workspace = true } 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { workspace = true, features = ["testutils"] } 16 | -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/contracts/hello_world/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec}; 3 | 4 | #[contract] 5 | pub struct HelloContract; 6 | 7 | 8 | #[contractimpl] 9 | impl HelloContract { 10 | pub fn hello(env: Env, to: Symbol) -> Vec { 11 | vec![&env, symbol_short!("Hello"), to] 12 | } 13 | } 14 | 15 | mod test; 16 | -------------------------------------------------------------------------------- /aula03/soroban-smartcontracts/contracts/hello_world/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | use soroban_sdk::{symbol_short, vec, Env}; 5 | 6 | #[test] 7 | fn test() { 8 | let env = Env::default(); 9 | let contract_id = env.register_contract(None, HelloContract); 10 | let client = HelloContractClient::new(&env, &contract_id); 11 | 12 | let words = client.hello(&symbol_short!("Dev")); 13 | assert_eq!( 14 | words, 15 | vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),] 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /aula04/README.md: -------------------------------------------------------------------------------- 1 | # Soroban 101 2 | 3 | ## 1. Flipper 4 | 5 | ## 2. Counter 6 | 7 | ## 3. Task Manager 8 | 9 | 10 | 11 | ## 1. config networking 12 | 13 | ``` 14 | soroban config network add local \ 15 | --rpc-url "http://localhost:8000/soroban/rpc" \ 16 | --network-passphrase "Standalone Network ; February 2017" 17 | ``` 18 | 19 | ## 2. config wallet 20 | 21 | ``` 22 | soroban keys generate --global bob --network local 23 | ``` 24 | 25 | ## 3. build smartcontracts 26 | 27 | ``` 28 | soroban contract build 29 | ``` 30 | 31 | ## 4. deploy smartcontract 32 | 33 | ``` 34 | soroban contract deploy \ 35 | --wasm target/wasm32-unknown-unknown/release/.wasm \ 36 | --source bob \ 37 | --network local 38 | ``` 39 | 40 | ## 5. interact with smartcontract 41 | 42 | ``` 43 | soroban contract invoke \ 44 | --id \ 45 | --source bob \ 46 | --network local \ 47 | -- \ 48 | hello \ 49 | --to Lucas 50 | ``` 51 | 52 | ```bash 53 | soroban contract invoke \ 54 | --id CDGRZ4K2YZAP2LWU5XTCAQM3AF5MD4QWY6KZO274OJ7PSFW6BJIRQPDV \ 55 | --source bob \ 56 | --network local \ 57 | -- \ 58 | get_all_tasks 59 | ``` 60 | 61 | ```bash 62 | soroban contract invoke \ 63 | --id CDGRZ4K2YZAP2LWU5XTCAQM3AF5MD4QWY6KZO274OJ7PSFW6BJIRQPDV \ 64 | --source bob \ 65 | --network local \ 66 | -- \ 67 | add_task \ 68 | --name Limpar_o_carro 69 | ``` 70 | 71 | ```bash 72 | soroban contract invoke \ 73 | --id CDGRZ4K2YZAP2LWU5XTCAQM3AF5MD4QWY6KZO274OJ7PSFW6BJIRQPDV \ 74 | --source bob \ 75 | --network local \ 76 | -- \ 77 | complete_task \ 78 | --id 1 79 | ``` 80 | 81 | ```bash 82 | soroban contract invoke \ 83 | --id CDGRZ4K2YZAP2LWU5XTCAQM3AF5MD4QWY6KZO274OJ7PSFW6BJIRQPDV \ 84 | --source bob \ 85 | --network local \ 86 | -- \ 87 | delete_task \ 88 | --id 12 89 | ``` -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/.gitignore: -------------------------------------------------------------------------------- 1 | # Rust's output directory 2 | target 3 | 4 | # Local Soroban settings 5 | .soroban 6 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "contracts/*", 5 | ] 6 | 7 | [workspace.dependencies] 8 | soroban-sdk = "20.3.2" 9 | 10 | [profile.release] 11 | opt-level = "z" 12 | overflow-checks = true 13 | debug = 0 14 | strip = "symbols" 15 | debug-assertions = false 16 | panic = "abort" 17 | codegen-units = 1 18 | lto = true 19 | 20 | # For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile 21 | [profile.release-with-logs] 22 | inherits = "release" 23 | debug-assertions = true 24 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/README.md: -------------------------------------------------------------------------------- 1 | # Soroban Project 2 | 3 | ## Project Structure 4 | 5 | This repository uses the recommended structure for a Soroban project: 6 | 7 | ```text 8 | . 9 | ├── contracts 10 | │   └── hello_world 11 | │   ├── src 12 | │   │   ├── lib.rs 13 | │   │   └── test.rs 14 | │   └── Cargo.toml 15 | ├── Cargo.toml 16 | └── README.md 17 | ``` 18 | 19 | - New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. 20 | - If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. 21 | - Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. 22 | - Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flipper" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | doctest = false 10 | 11 | [dependencies] 12 | soroban-sdk = { workspace = true } 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { workspace = true, features = ["testutils"] } 16 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 3 | 4 | const STATE: Symbol = symbol_short!("STATE"); 5 | 6 | 7 | // enum Result { 8 | // OK(bool), 9 | // Error(Symbol), 10 | // } 11 | 12 | 13 | #[contract] 14 | pub struct Flipper; 15 | 16 | #[contractimpl] 17 | impl Flipper { 18 | 19 | pub fn flip(env: Env) { 20 | let mut state: bool = env.storage().instance().get(&STATE).unwrap_or(false); 21 | 22 | state = !state; 23 | 24 | env.storage().instance().set(&STATE, &state); 25 | } 26 | 27 | pub fn get_state(env: Env) -> bool { 28 | env.storage().instance().get(&STATE).unwrap_or(false) 29 | } 30 | } 31 | 32 | mod test; 33 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | use soroban_sdk::Env; 5 | 6 | #[test] 7 | fn simple_test() { 8 | let env = Env::default(); 9 | let contract_id = env.register_contract(None, Flipper); 10 | let client = FlipperClient::new(&env, &contract_id); 11 | 12 | let current_state = client.get_state(); 13 | assert_eq!(current_state, false); 14 | 15 | client.flip(); 16 | 17 | let current_state = client.get_state(); 18 | assert_eq!(current_state, true); 19 | } 20 | 21 | #[test] 22 | fn multiple_flips_test() { 23 | let env = Env::default(); 24 | let contract_id = env.register_contract(None, Flipper); 25 | let client = FlipperClient::new(&env, &contract_id); 26 | 27 | let current_state = client.get_state(); 28 | assert_eq!(current_state, false); 29 | 30 | client.flip(); // to true 31 | client.flip(); // to false 32 | client.flip(); // to true 33 | client.flip(); // to false 34 | client.flip(); // to true 35 | client.flip(); // to false 36 | 37 | let current_state = client.get_state(); 38 | assert_eq!(current_state, false); 39 | } 40 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/test_snapshots/test/multiple_flips_test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [], 10 | [], 11 | [], 12 | [], 13 | [], 14 | [] 15 | ], 16 | "ledger": { 17 | "protocol_version": 20, 18 | "sequence_number": 0, 19 | "timestamp": 0, 20 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 21 | "base_reserve": 0, 22 | "min_persistent_entry_ttl": 4096, 23 | "min_temp_entry_ttl": 16, 24 | "max_entry_ttl": 6312000, 25 | "ledger_entries": [ 26 | [ 27 | { 28 | "contract_data": { 29 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 30 | "key": "ledger_key_contract_instance", 31 | "durability": "persistent" 32 | } 33 | }, 34 | [ 35 | { 36 | "last_modified_ledger_seq": 0, 37 | "data": { 38 | "contract_data": { 39 | "ext": "v0", 40 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 41 | "key": "ledger_key_contract_instance", 42 | "durability": "persistent", 43 | "val": { 44 | "contract_instance": { 45 | "executable": { 46 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 47 | }, 48 | "storage": [ 49 | { 50 | "key": { 51 | "symbol": "STATE" 52 | }, 53 | "val": { 54 | "bool": false 55 | } 56 | } 57 | ] 58 | } 59 | } 60 | } 61 | }, 62 | "ext": "v0" 63 | }, 64 | 4095 65 | ] 66 | ], 67 | [ 68 | { 69 | "contract_code": { 70 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 71 | } 72 | }, 73 | [ 74 | { 75 | "last_modified_ledger_seq": 0, 76 | "data": { 77 | "contract_code": { 78 | "ext": "v0", 79 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 80 | "code": "" 81 | } 82 | }, 83 | "ext": "v0" 84 | }, 85 | 4095 86 | ] 87 | ] 88 | ] 89 | }, 90 | "events": [ 91 | { 92 | "event": { 93 | "ext": "v0", 94 | "contract_id": null, 95 | "type_": "diagnostic", 96 | "body": { 97 | "v0": { 98 | "topics": [ 99 | { 100 | "symbol": "fn_call" 101 | }, 102 | { 103 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 104 | }, 105 | { 106 | "symbol": "get_state" 107 | } 108 | ], 109 | "data": "void" 110 | } 111 | } 112 | }, 113 | "failed_call": false 114 | }, 115 | { 116 | "event": { 117 | "ext": "v0", 118 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 119 | "type_": "diagnostic", 120 | "body": { 121 | "v0": { 122 | "topics": [ 123 | { 124 | "symbol": "fn_return" 125 | }, 126 | { 127 | "symbol": "get_state" 128 | } 129 | ], 130 | "data": { 131 | "bool": false 132 | } 133 | } 134 | } 135 | }, 136 | "failed_call": false 137 | }, 138 | { 139 | "event": { 140 | "ext": "v0", 141 | "contract_id": null, 142 | "type_": "diagnostic", 143 | "body": { 144 | "v0": { 145 | "topics": [ 146 | { 147 | "symbol": "fn_call" 148 | }, 149 | { 150 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 151 | }, 152 | { 153 | "symbol": "flip" 154 | } 155 | ], 156 | "data": "void" 157 | } 158 | } 159 | }, 160 | "failed_call": false 161 | }, 162 | { 163 | "event": { 164 | "ext": "v0", 165 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 166 | "type_": "diagnostic", 167 | "body": { 168 | "v0": { 169 | "topics": [ 170 | { 171 | "symbol": "fn_return" 172 | }, 173 | { 174 | "symbol": "flip" 175 | } 176 | ], 177 | "data": "void" 178 | } 179 | } 180 | }, 181 | "failed_call": false 182 | }, 183 | { 184 | "event": { 185 | "ext": "v0", 186 | "contract_id": null, 187 | "type_": "diagnostic", 188 | "body": { 189 | "v0": { 190 | "topics": [ 191 | { 192 | "symbol": "fn_call" 193 | }, 194 | { 195 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 196 | }, 197 | { 198 | "symbol": "flip" 199 | } 200 | ], 201 | "data": "void" 202 | } 203 | } 204 | }, 205 | "failed_call": false 206 | }, 207 | { 208 | "event": { 209 | "ext": "v0", 210 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 211 | "type_": "diagnostic", 212 | "body": { 213 | "v0": { 214 | "topics": [ 215 | { 216 | "symbol": "fn_return" 217 | }, 218 | { 219 | "symbol": "flip" 220 | } 221 | ], 222 | "data": "void" 223 | } 224 | } 225 | }, 226 | "failed_call": false 227 | }, 228 | { 229 | "event": { 230 | "ext": "v0", 231 | "contract_id": null, 232 | "type_": "diagnostic", 233 | "body": { 234 | "v0": { 235 | "topics": [ 236 | { 237 | "symbol": "fn_call" 238 | }, 239 | { 240 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 241 | }, 242 | { 243 | "symbol": "flip" 244 | } 245 | ], 246 | "data": "void" 247 | } 248 | } 249 | }, 250 | "failed_call": false 251 | }, 252 | { 253 | "event": { 254 | "ext": "v0", 255 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 256 | "type_": "diagnostic", 257 | "body": { 258 | "v0": { 259 | "topics": [ 260 | { 261 | "symbol": "fn_return" 262 | }, 263 | { 264 | "symbol": "flip" 265 | } 266 | ], 267 | "data": "void" 268 | } 269 | } 270 | }, 271 | "failed_call": false 272 | }, 273 | { 274 | "event": { 275 | "ext": "v0", 276 | "contract_id": null, 277 | "type_": "diagnostic", 278 | "body": { 279 | "v0": { 280 | "topics": [ 281 | { 282 | "symbol": "fn_call" 283 | }, 284 | { 285 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 286 | }, 287 | { 288 | "symbol": "flip" 289 | } 290 | ], 291 | "data": "void" 292 | } 293 | } 294 | }, 295 | "failed_call": false 296 | }, 297 | { 298 | "event": { 299 | "ext": "v0", 300 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 301 | "type_": "diagnostic", 302 | "body": { 303 | "v0": { 304 | "topics": [ 305 | { 306 | "symbol": "fn_return" 307 | }, 308 | { 309 | "symbol": "flip" 310 | } 311 | ], 312 | "data": "void" 313 | } 314 | } 315 | }, 316 | "failed_call": false 317 | }, 318 | { 319 | "event": { 320 | "ext": "v0", 321 | "contract_id": null, 322 | "type_": "diagnostic", 323 | "body": { 324 | "v0": { 325 | "topics": [ 326 | { 327 | "symbol": "fn_call" 328 | }, 329 | { 330 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 331 | }, 332 | { 333 | "symbol": "flip" 334 | } 335 | ], 336 | "data": "void" 337 | } 338 | } 339 | }, 340 | "failed_call": false 341 | }, 342 | { 343 | "event": { 344 | "ext": "v0", 345 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 346 | "type_": "diagnostic", 347 | "body": { 348 | "v0": { 349 | "topics": [ 350 | { 351 | "symbol": "fn_return" 352 | }, 353 | { 354 | "symbol": "flip" 355 | } 356 | ], 357 | "data": "void" 358 | } 359 | } 360 | }, 361 | "failed_call": false 362 | }, 363 | { 364 | "event": { 365 | "ext": "v0", 366 | "contract_id": null, 367 | "type_": "diagnostic", 368 | "body": { 369 | "v0": { 370 | "topics": [ 371 | { 372 | "symbol": "fn_call" 373 | }, 374 | { 375 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 376 | }, 377 | { 378 | "symbol": "flip" 379 | } 380 | ], 381 | "data": "void" 382 | } 383 | } 384 | }, 385 | "failed_call": false 386 | }, 387 | { 388 | "event": { 389 | "ext": "v0", 390 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 391 | "type_": "diagnostic", 392 | "body": { 393 | "v0": { 394 | "topics": [ 395 | { 396 | "symbol": "fn_return" 397 | }, 398 | { 399 | "symbol": "flip" 400 | } 401 | ], 402 | "data": "void" 403 | } 404 | } 405 | }, 406 | "failed_call": false 407 | }, 408 | { 409 | "event": { 410 | "ext": "v0", 411 | "contract_id": null, 412 | "type_": "diagnostic", 413 | "body": { 414 | "v0": { 415 | "topics": [ 416 | { 417 | "symbol": "fn_call" 418 | }, 419 | { 420 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 421 | }, 422 | { 423 | "symbol": "get_state" 424 | } 425 | ], 426 | "data": "void" 427 | } 428 | } 429 | }, 430 | "failed_call": false 431 | }, 432 | { 433 | "event": { 434 | "ext": "v0", 435 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 436 | "type_": "diagnostic", 437 | "body": { 438 | "v0": { 439 | "topics": [ 440 | { 441 | "symbol": "fn_return" 442 | }, 443 | { 444 | "symbol": "get_state" 445 | } 446 | ], 447 | "data": { 448 | "bool": false 449 | } 450 | } 451 | } 452 | }, 453 | "failed_call": false 454 | } 455 | ] 456 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/test_snapshots/test/simple_test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [] 10 | ], 11 | "ledger": { 12 | "protocol_version": 20, 13 | "sequence_number": 0, 14 | "timestamp": 0, 15 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 16 | "base_reserve": 0, 17 | "min_persistent_entry_ttl": 4096, 18 | "min_temp_entry_ttl": 16, 19 | "max_entry_ttl": 6312000, 20 | "ledger_entries": [ 21 | [ 22 | { 23 | "contract_data": { 24 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 25 | "key": "ledger_key_contract_instance", 26 | "durability": "persistent" 27 | } 28 | }, 29 | [ 30 | { 31 | "last_modified_ledger_seq": 0, 32 | "data": { 33 | "contract_data": { 34 | "ext": "v0", 35 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 36 | "key": "ledger_key_contract_instance", 37 | "durability": "persistent", 38 | "val": { 39 | "contract_instance": { 40 | "executable": { 41 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 42 | }, 43 | "storage": [ 44 | { 45 | "key": { 46 | "symbol": "STATE" 47 | }, 48 | "val": { 49 | "bool": true 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | }, 57 | "ext": "v0" 58 | }, 59 | 4095 60 | ] 61 | ], 62 | [ 63 | { 64 | "contract_code": { 65 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 66 | } 67 | }, 68 | [ 69 | { 70 | "last_modified_ledger_seq": 0, 71 | "data": { 72 | "contract_code": { 73 | "ext": "v0", 74 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 75 | "code": "" 76 | } 77 | }, 78 | "ext": "v0" 79 | }, 80 | 4095 81 | ] 82 | ] 83 | ] 84 | }, 85 | "events": [ 86 | { 87 | "event": { 88 | "ext": "v0", 89 | "contract_id": null, 90 | "type_": "diagnostic", 91 | "body": { 92 | "v0": { 93 | "topics": [ 94 | { 95 | "symbol": "fn_call" 96 | }, 97 | { 98 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 99 | }, 100 | { 101 | "symbol": "get_state" 102 | } 103 | ], 104 | "data": "void" 105 | } 106 | } 107 | }, 108 | "failed_call": false 109 | }, 110 | { 111 | "event": { 112 | "ext": "v0", 113 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 114 | "type_": "diagnostic", 115 | "body": { 116 | "v0": { 117 | "topics": [ 118 | { 119 | "symbol": "fn_return" 120 | }, 121 | { 122 | "symbol": "get_state" 123 | } 124 | ], 125 | "data": { 126 | "bool": false 127 | } 128 | } 129 | } 130 | }, 131 | "failed_call": false 132 | }, 133 | { 134 | "event": { 135 | "ext": "v0", 136 | "contract_id": null, 137 | "type_": "diagnostic", 138 | "body": { 139 | "v0": { 140 | "topics": [ 141 | { 142 | "symbol": "fn_call" 143 | }, 144 | { 145 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 146 | }, 147 | { 148 | "symbol": "flip" 149 | } 150 | ], 151 | "data": "void" 152 | } 153 | } 154 | }, 155 | "failed_call": false 156 | }, 157 | { 158 | "event": { 159 | "ext": "v0", 160 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 161 | "type_": "diagnostic", 162 | "body": { 163 | "v0": { 164 | "topics": [ 165 | { 166 | "symbol": "fn_return" 167 | }, 168 | { 169 | "symbol": "flip" 170 | } 171 | ], 172 | "data": "void" 173 | } 174 | } 175 | }, 176 | "failed_call": false 177 | }, 178 | { 179 | "event": { 180 | "ext": "v0", 181 | "contract_id": null, 182 | "type_": "diagnostic", 183 | "body": { 184 | "v0": { 185 | "topics": [ 186 | { 187 | "symbol": "fn_call" 188 | }, 189 | { 190 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 191 | }, 192 | { 193 | "symbol": "get_state" 194 | } 195 | ], 196 | "data": "void" 197 | } 198 | } 199 | }, 200 | "failed_call": false 201 | }, 202 | { 203 | "event": { 204 | "ext": "v0", 205 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 206 | "type_": "diagnostic", 207 | "body": { 208 | "v0": { 209 | "topics": [ 210 | { 211 | "symbol": "fn_return" 212 | }, 213 | { 214 | "symbol": "get_state" 215 | } 216 | ], 217 | "data": { 218 | "bool": true 219 | } 220 | } 221 | } 222 | }, 223 | "failed_call": false 224 | } 225 | ] 226 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/flipper/test_snapshots/test/test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [] 10 | ], 11 | "ledger": { 12 | "protocol_version": 20, 13 | "sequence_number": 0, 14 | "timestamp": 0, 15 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 16 | "base_reserve": 0, 17 | "min_persistent_entry_ttl": 4096, 18 | "min_temp_entry_ttl": 16, 19 | "max_entry_ttl": 6312000, 20 | "ledger_entries": [ 21 | [ 22 | { 23 | "contract_data": { 24 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 25 | "key": "ledger_key_contract_instance", 26 | "durability": "persistent" 27 | } 28 | }, 29 | [ 30 | { 31 | "last_modified_ledger_seq": 0, 32 | "data": { 33 | "contract_data": { 34 | "ext": "v0", 35 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 36 | "key": "ledger_key_contract_instance", 37 | "durability": "persistent", 38 | "val": { 39 | "contract_instance": { 40 | "executable": { 41 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 42 | }, 43 | "storage": [ 44 | { 45 | "key": { 46 | "symbol": "STATE" 47 | }, 48 | "val": { 49 | "bool": true 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | }, 57 | "ext": "v0" 58 | }, 59 | 4095 60 | ] 61 | ], 62 | [ 63 | { 64 | "contract_code": { 65 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 66 | } 67 | }, 68 | [ 69 | { 70 | "last_modified_ledger_seq": 0, 71 | "data": { 72 | "contract_code": { 73 | "ext": "v0", 74 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 75 | "code": "" 76 | } 77 | }, 78 | "ext": "v0" 79 | }, 80 | 4095 81 | ] 82 | ] 83 | ] 84 | }, 85 | "events": [ 86 | { 87 | "event": { 88 | "ext": "v0", 89 | "contract_id": null, 90 | "type_": "diagnostic", 91 | "body": { 92 | "v0": { 93 | "topics": [ 94 | { 95 | "symbol": "fn_call" 96 | }, 97 | { 98 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 99 | }, 100 | { 101 | "symbol": "get_state" 102 | } 103 | ], 104 | "data": "void" 105 | } 106 | } 107 | }, 108 | "failed_call": false 109 | }, 110 | { 111 | "event": { 112 | "ext": "v0", 113 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 114 | "type_": "diagnostic", 115 | "body": { 116 | "v0": { 117 | "topics": [ 118 | { 119 | "symbol": "fn_return" 120 | }, 121 | { 122 | "symbol": "get_state" 123 | } 124 | ], 125 | "data": { 126 | "bool": false 127 | } 128 | } 129 | } 130 | }, 131 | "failed_call": false 132 | }, 133 | { 134 | "event": { 135 | "ext": "v0", 136 | "contract_id": null, 137 | "type_": "diagnostic", 138 | "body": { 139 | "v0": { 140 | "topics": [ 141 | { 142 | "symbol": "fn_call" 143 | }, 144 | { 145 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 146 | }, 147 | { 148 | "symbol": "flip" 149 | } 150 | ], 151 | "data": "void" 152 | } 153 | } 154 | }, 155 | "failed_call": false 156 | }, 157 | { 158 | "event": { 159 | "ext": "v0", 160 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 161 | "type_": "diagnostic", 162 | "body": { 163 | "v0": { 164 | "topics": [ 165 | { 166 | "symbol": "fn_return" 167 | }, 168 | { 169 | "symbol": "flip" 170 | } 171 | ], 172 | "data": "void" 173 | } 174 | } 175 | }, 176 | "failed_call": false 177 | }, 178 | { 179 | "event": { 180 | "ext": "v0", 181 | "contract_id": null, 182 | "type_": "diagnostic", 183 | "body": { 184 | "v0": { 185 | "topics": [ 186 | { 187 | "symbol": "fn_call" 188 | }, 189 | { 190 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 191 | }, 192 | { 193 | "symbol": "get_state" 194 | } 195 | ], 196 | "data": "void" 197 | } 198 | } 199 | }, 200 | "failed_call": false 201 | }, 202 | { 203 | "event": { 204 | "ext": "v0", 205 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 206 | "type_": "diagnostic", 207 | "body": { 208 | "v0": { 209 | "topics": [ 210 | { 211 | "symbol": "fn_return" 212 | }, 213 | { 214 | "symbol": "get_state" 215 | } 216 | ], 217 | "data": { 218 | "bool": true 219 | } 220 | } 221 | } 222 | }, 223 | "failed_call": false 224 | } 225 | ] 226 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "increment" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | doctest = false 10 | 11 | [dependencies] 12 | soroban-sdk = { workspace = true } 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { version = "20.3.1", features = ["testutils"] } 16 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, log, symbol_short, Env, Symbol}; 3 | 4 | const COUNTER: Symbol = symbol_short!("COUNTER"); 5 | 6 | #[contract] 7 | pub struct IncrementContract; 8 | 9 | #[contractimpl] 10 | impl IncrementContract { 11 | /// Increment increments an internal counter, and returns the value. 12 | pub fn increment(env: Env) { 13 | // Get the current count. 14 | let mut count: u32 = env.storage().instance().get(&COUNTER).unwrap_or(0); // If no value set, assume 0. 15 | log!(&env, "count: {}", count); 16 | 17 | // Increment the count. 18 | count += 1; 19 | 20 | // Save the count. 21 | env.storage().instance().set(&COUNTER, &count); 22 | 23 | // The contract instance will be bumped to have a lifetime of at least 100 ledgers if the current expiration lifetime at most 50. 24 | // If the lifetime is already more than 100 ledgers, this is a no-op. Otherwise, 25 | // the lifetime is extended to 100 ledgers. This lifetime bump includes the contract 26 | // instance itself and all entries in storage().instance(), i.e, COUNTER. 27 | env.storage().instance().extend_ttl(50, 100); 28 | } 29 | 30 | pub fn get_counter(env: Env) -> u32 { 31 | env.storage().instance().get(&COUNTER).unwrap_or(0) 32 | } 33 | } 34 | 35 | mod test; 36 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::{IncrementContract, IncrementContractClient}; 4 | use soroban_sdk::{testutils::Logs, Env}; 5 | 6 | extern crate std; 7 | 8 | #[test] 9 | fn simple_test() { 10 | let env = Env::default(); 11 | let contract_id = env.register_contract(None, IncrementContract); 12 | let client = IncrementContractClient::new(&env, &contract_id); 13 | 14 | assert_eq!(client.get_counter(), 0); 15 | client.increment(); 16 | assert_eq!(client.get_counter(), 1); 17 | 18 | std::println!("{}", env.logs().all().join("\n")); 19 | } 20 | 21 | #[test] 22 | fn multiple_increments_test() { 23 | let env = Env::default(); 24 | let contract_id = env.register_contract(None, IncrementContract); 25 | let client = IncrementContractClient::new(&env, &contract_id); 26 | 27 | assert_eq!(client.get_counter(), 0); 28 | client.increment(); // +1 => 1 29 | client.increment(); // +1 => 2 30 | client.increment(); // +1 => 3 31 | client.increment(); // +1 => 4 32 | client.increment(); // +1 => 5 33 | client.increment(); // +1 => 6 34 | client.increment(); // +1 => 7 35 | assert_eq!(client.get_counter(), 7); 36 | 37 | std::println!("{}", env.logs().all().join("\n")); 38 | } 39 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/test_snapshots/test/multiple_increments_test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [], 10 | [], 11 | [], 12 | [], 13 | [], 14 | [], 15 | [] 16 | ], 17 | "ledger": { 18 | "protocol_version": 20, 19 | "sequence_number": 0, 20 | "timestamp": 0, 21 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 22 | "base_reserve": 0, 23 | "min_persistent_entry_ttl": 4096, 24 | "min_temp_entry_ttl": 16, 25 | "max_entry_ttl": 6312000, 26 | "ledger_entries": [ 27 | [ 28 | { 29 | "contract_data": { 30 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 31 | "key": "ledger_key_contract_instance", 32 | "durability": "persistent" 33 | } 34 | }, 35 | [ 36 | { 37 | "last_modified_ledger_seq": 0, 38 | "data": { 39 | "contract_data": { 40 | "ext": "v0", 41 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 42 | "key": "ledger_key_contract_instance", 43 | "durability": "persistent", 44 | "val": { 45 | "contract_instance": { 46 | "executable": { 47 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 48 | }, 49 | "storage": [ 50 | { 51 | "key": { 52 | "symbol": "COUNTER" 53 | }, 54 | "val": { 55 | "u32": 7 56 | } 57 | } 58 | ] 59 | } 60 | } 61 | } 62 | }, 63 | "ext": "v0" 64 | }, 65 | 4095 66 | ] 67 | ], 68 | [ 69 | { 70 | "contract_code": { 71 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 72 | } 73 | }, 74 | [ 75 | { 76 | "last_modified_ledger_seq": 0, 77 | "data": { 78 | "contract_code": { 79 | "ext": "v0", 80 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 81 | "code": "" 82 | } 83 | }, 84 | "ext": "v0" 85 | }, 86 | 4095 87 | ] 88 | ] 89 | ] 90 | }, 91 | "events": [ 92 | { 93 | "event": { 94 | "ext": "v0", 95 | "contract_id": null, 96 | "type_": "diagnostic", 97 | "body": { 98 | "v0": { 99 | "topics": [ 100 | { 101 | "symbol": "fn_call" 102 | }, 103 | { 104 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 105 | }, 106 | { 107 | "symbol": "get_counter" 108 | } 109 | ], 110 | "data": "void" 111 | } 112 | } 113 | }, 114 | "failed_call": false 115 | }, 116 | { 117 | "event": { 118 | "ext": "v0", 119 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 120 | "type_": "diagnostic", 121 | "body": { 122 | "v0": { 123 | "topics": [ 124 | { 125 | "symbol": "fn_return" 126 | }, 127 | { 128 | "symbol": "get_counter" 129 | } 130 | ], 131 | "data": { 132 | "u32": 0 133 | } 134 | } 135 | } 136 | }, 137 | "failed_call": false 138 | }, 139 | { 140 | "event": { 141 | "ext": "v0", 142 | "contract_id": null, 143 | "type_": "diagnostic", 144 | "body": { 145 | "v0": { 146 | "topics": [ 147 | { 148 | "symbol": "fn_call" 149 | }, 150 | { 151 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 152 | }, 153 | { 154 | "symbol": "increment" 155 | } 156 | ], 157 | "data": "void" 158 | } 159 | } 160 | }, 161 | "failed_call": false 162 | }, 163 | { 164 | "event": { 165 | "ext": "v0", 166 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 167 | "type_": "diagnostic", 168 | "body": { 169 | "v0": { 170 | "topics": [ 171 | { 172 | "symbol": "log" 173 | } 174 | ], 175 | "data": { 176 | "vec": [ 177 | { 178 | "string": "count: {}" 179 | }, 180 | { 181 | "u32": 0 182 | } 183 | ] 184 | } 185 | } 186 | } 187 | }, 188 | "failed_call": false 189 | }, 190 | { 191 | "event": { 192 | "ext": "v0", 193 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 194 | "type_": "diagnostic", 195 | "body": { 196 | "v0": { 197 | "topics": [ 198 | { 199 | "symbol": "fn_return" 200 | }, 201 | { 202 | "symbol": "increment" 203 | } 204 | ], 205 | "data": "void" 206 | } 207 | } 208 | }, 209 | "failed_call": false 210 | }, 211 | { 212 | "event": { 213 | "ext": "v0", 214 | "contract_id": null, 215 | "type_": "diagnostic", 216 | "body": { 217 | "v0": { 218 | "topics": [ 219 | { 220 | "symbol": "fn_call" 221 | }, 222 | { 223 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 224 | }, 225 | { 226 | "symbol": "increment" 227 | } 228 | ], 229 | "data": "void" 230 | } 231 | } 232 | }, 233 | "failed_call": false 234 | }, 235 | { 236 | "event": { 237 | "ext": "v0", 238 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 239 | "type_": "diagnostic", 240 | "body": { 241 | "v0": { 242 | "topics": [ 243 | { 244 | "symbol": "log" 245 | } 246 | ], 247 | "data": { 248 | "vec": [ 249 | { 250 | "string": "count: {}" 251 | }, 252 | { 253 | "u32": 1 254 | } 255 | ] 256 | } 257 | } 258 | } 259 | }, 260 | "failed_call": false 261 | }, 262 | { 263 | "event": { 264 | "ext": "v0", 265 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 266 | "type_": "diagnostic", 267 | "body": { 268 | "v0": { 269 | "topics": [ 270 | { 271 | "symbol": "fn_return" 272 | }, 273 | { 274 | "symbol": "increment" 275 | } 276 | ], 277 | "data": "void" 278 | } 279 | } 280 | }, 281 | "failed_call": false 282 | }, 283 | { 284 | "event": { 285 | "ext": "v0", 286 | "contract_id": null, 287 | "type_": "diagnostic", 288 | "body": { 289 | "v0": { 290 | "topics": [ 291 | { 292 | "symbol": "fn_call" 293 | }, 294 | { 295 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 296 | }, 297 | { 298 | "symbol": "increment" 299 | } 300 | ], 301 | "data": "void" 302 | } 303 | } 304 | }, 305 | "failed_call": false 306 | }, 307 | { 308 | "event": { 309 | "ext": "v0", 310 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 311 | "type_": "diagnostic", 312 | "body": { 313 | "v0": { 314 | "topics": [ 315 | { 316 | "symbol": "log" 317 | } 318 | ], 319 | "data": { 320 | "vec": [ 321 | { 322 | "string": "count: {}" 323 | }, 324 | { 325 | "u32": 2 326 | } 327 | ] 328 | } 329 | } 330 | } 331 | }, 332 | "failed_call": false 333 | }, 334 | { 335 | "event": { 336 | "ext": "v0", 337 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 338 | "type_": "diagnostic", 339 | "body": { 340 | "v0": { 341 | "topics": [ 342 | { 343 | "symbol": "fn_return" 344 | }, 345 | { 346 | "symbol": "increment" 347 | } 348 | ], 349 | "data": "void" 350 | } 351 | } 352 | }, 353 | "failed_call": false 354 | }, 355 | { 356 | "event": { 357 | "ext": "v0", 358 | "contract_id": null, 359 | "type_": "diagnostic", 360 | "body": { 361 | "v0": { 362 | "topics": [ 363 | { 364 | "symbol": "fn_call" 365 | }, 366 | { 367 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 368 | }, 369 | { 370 | "symbol": "increment" 371 | } 372 | ], 373 | "data": "void" 374 | } 375 | } 376 | }, 377 | "failed_call": false 378 | }, 379 | { 380 | "event": { 381 | "ext": "v0", 382 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 383 | "type_": "diagnostic", 384 | "body": { 385 | "v0": { 386 | "topics": [ 387 | { 388 | "symbol": "log" 389 | } 390 | ], 391 | "data": { 392 | "vec": [ 393 | { 394 | "string": "count: {}" 395 | }, 396 | { 397 | "u32": 3 398 | } 399 | ] 400 | } 401 | } 402 | } 403 | }, 404 | "failed_call": false 405 | }, 406 | { 407 | "event": { 408 | "ext": "v0", 409 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 410 | "type_": "diagnostic", 411 | "body": { 412 | "v0": { 413 | "topics": [ 414 | { 415 | "symbol": "fn_return" 416 | }, 417 | { 418 | "symbol": "increment" 419 | } 420 | ], 421 | "data": "void" 422 | } 423 | } 424 | }, 425 | "failed_call": false 426 | }, 427 | { 428 | "event": { 429 | "ext": "v0", 430 | "contract_id": null, 431 | "type_": "diagnostic", 432 | "body": { 433 | "v0": { 434 | "topics": [ 435 | { 436 | "symbol": "fn_call" 437 | }, 438 | { 439 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 440 | }, 441 | { 442 | "symbol": "increment" 443 | } 444 | ], 445 | "data": "void" 446 | } 447 | } 448 | }, 449 | "failed_call": false 450 | }, 451 | { 452 | "event": { 453 | "ext": "v0", 454 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 455 | "type_": "diagnostic", 456 | "body": { 457 | "v0": { 458 | "topics": [ 459 | { 460 | "symbol": "log" 461 | } 462 | ], 463 | "data": { 464 | "vec": [ 465 | { 466 | "string": "count: {}" 467 | }, 468 | { 469 | "u32": 4 470 | } 471 | ] 472 | } 473 | } 474 | } 475 | }, 476 | "failed_call": false 477 | }, 478 | { 479 | "event": { 480 | "ext": "v0", 481 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 482 | "type_": "diagnostic", 483 | "body": { 484 | "v0": { 485 | "topics": [ 486 | { 487 | "symbol": "fn_return" 488 | }, 489 | { 490 | "symbol": "increment" 491 | } 492 | ], 493 | "data": "void" 494 | } 495 | } 496 | }, 497 | "failed_call": false 498 | }, 499 | { 500 | "event": { 501 | "ext": "v0", 502 | "contract_id": null, 503 | "type_": "diagnostic", 504 | "body": { 505 | "v0": { 506 | "topics": [ 507 | { 508 | "symbol": "fn_call" 509 | }, 510 | { 511 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 512 | }, 513 | { 514 | "symbol": "increment" 515 | } 516 | ], 517 | "data": "void" 518 | } 519 | } 520 | }, 521 | "failed_call": false 522 | }, 523 | { 524 | "event": { 525 | "ext": "v0", 526 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 527 | "type_": "diagnostic", 528 | "body": { 529 | "v0": { 530 | "topics": [ 531 | { 532 | "symbol": "log" 533 | } 534 | ], 535 | "data": { 536 | "vec": [ 537 | { 538 | "string": "count: {}" 539 | }, 540 | { 541 | "u32": 5 542 | } 543 | ] 544 | } 545 | } 546 | } 547 | }, 548 | "failed_call": false 549 | }, 550 | { 551 | "event": { 552 | "ext": "v0", 553 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 554 | "type_": "diagnostic", 555 | "body": { 556 | "v0": { 557 | "topics": [ 558 | { 559 | "symbol": "fn_return" 560 | }, 561 | { 562 | "symbol": "increment" 563 | } 564 | ], 565 | "data": "void" 566 | } 567 | } 568 | }, 569 | "failed_call": false 570 | }, 571 | { 572 | "event": { 573 | "ext": "v0", 574 | "contract_id": null, 575 | "type_": "diagnostic", 576 | "body": { 577 | "v0": { 578 | "topics": [ 579 | { 580 | "symbol": "fn_call" 581 | }, 582 | { 583 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 584 | }, 585 | { 586 | "symbol": "increment" 587 | } 588 | ], 589 | "data": "void" 590 | } 591 | } 592 | }, 593 | "failed_call": false 594 | }, 595 | { 596 | "event": { 597 | "ext": "v0", 598 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 599 | "type_": "diagnostic", 600 | "body": { 601 | "v0": { 602 | "topics": [ 603 | { 604 | "symbol": "log" 605 | } 606 | ], 607 | "data": { 608 | "vec": [ 609 | { 610 | "string": "count: {}" 611 | }, 612 | { 613 | "u32": 6 614 | } 615 | ] 616 | } 617 | } 618 | } 619 | }, 620 | "failed_call": false 621 | }, 622 | { 623 | "event": { 624 | "ext": "v0", 625 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 626 | "type_": "diagnostic", 627 | "body": { 628 | "v0": { 629 | "topics": [ 630 | { 631 | "symbol": "fn_return" 632 | }, 633 | { 634 | "symbol": "increment" 635 | } 636 | ], 637 | "data": "void" 638 | } 639 | } 640 | }, 641 | "failed_call": false 642 | }, 643 | { 644 | "event": { 645 | "ext": "v0", 646 | "contract_id": null, 647 | "type_": "diagnostic", 648 | "body": { 649 | "v0": { 650 | "topics": [ 651 | { 652 | "symbol": "fn_call" 653 | }, 654 | { 655 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 656 | }, 657 | { 658 | "symbol": "get_counter" 659 | } 660 | ], 661 | "data": "void" 662 | } 663 | } 664 | }, 665 | "failed_call": false 666 | }, 667 | { 668 | "event": { 669 | "ext": "v0", 670 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 671 | "type_": "diagnostic", 672 | "body": { 673 | "v0": { 674 | "topics": [ 675 | { 676 | "symbol": "fn_return" 677 | }, 678 | { 679 | "symbol": "get_counter" 680 | } 681 | ], 682 | "data": { 683 | "u32": 7 684 | } 685 | } 686 | } 687 | }, 688 | "failed_call": false 689 | } 690 | ] 691 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/test_snapshots/test/simple_test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [] 10 | ], 11 | "ledger": { 12 | "protocol_version": 20, 13 | "sequence_number": 0, 14 | "timestamp": 0, 15 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 16 | "base_reserve": 0, 17 | "min_persistent_entry_ttl": 4096, 18 | "min_temp_entry_ttl": 16, 19 | "max_entry_ttl": 6312000, 20 | "ledger_entries": [ 21 | [ 22 | { 23 | "contract_data": { 24 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 25 | "key": "ledger_key_contract_instance", 26 | "durability": "persistent" 27 | } 28 | }, 29 | [ 30 | { 31 | "last_modified_ledger_seq": 0, 32 | "data": { 33 | "contract_data": { 34 | "ext": "v0", 35 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 36 | "key": "ledger_key_contract_instance", 37 | "durability": "persistent", 38 | "val": { 39 | "contract_instance": { 40 | "executable": { 41 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 42 | }, 43 | "storage": [ 44 | { 45 | "key": { 46 | "symbol": "COUNTER" 47 | }, 48 | "val": { 49 | "u32": 1 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | }, 57 | "ext": "v0" 58 | }, 59 | 4095 60 | ] 61 | ], 62 | [ 63 | { 64 | "contract_code": { 65 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 66 | } 67 | }, 68 | [ 69 | { 70 | "last_modified_ledger_seq": 0, 71 | "data": { 72 | "contract_code": { 73 | "ext": "v0", 74 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 75 | "code": "" 76 | } 77 | }, 78 | "ext": "v0" 79 | }, 80 | 4095 81 | ] 82 | ] 83 | ] 84 | }, 85 | "events": [ 86 | { 87 | "event": { 88 | "ext": "v0", 89 | "contract_id": null, 90 | "type_": "diagnostic", 91 | "body": { 92 | "v0": { 93 | "topics": [ 94 | { 95 | "symbol": "fn_call" 96 | }, 97 | { 98 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 99 | }, 100 | { 101 | "symbol": "get_counter" 102 | } 103 | ], 104 | "data": "void" 105 | } 106 | } 107 | }, 108 | "failed_call": false 109 | }, 110 | { 111 | "event": { 112 | "ext": "v0", 113 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 114 | "type_": "diagnostic", 115 | "body": { 116 | "v0": { 117 | "topics": [ 118 | { 119 | "symbol": "fn_return" 120 | }, 121 | { 122 | "symbol": "get_counter" 123 | } 124 | ], 125 | "data": { 126 | "u32": 0 127 | } 128 | } 129 | } 130 | }, 131 | "failed_call": false 132 | }, 133 | { 134 | "event": { 135 | "ext": "v0", 136 | "contract_id": null, 137 | "type_": "diagnostic", 138 | "body": { 139 | "v0": { 140 | "topics": [ 141 | { 142 | "symbol": "fn_call" 143 | }, 144 | { 145 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 146 | }, 147 | { 148 | "symbol": "increment" 149 | } 150 | ], 151 | "data": "void" 152 | } 153 | } 154 | }, 155 | "failed_call": false 156 | }, 157 | { 158 | "event": { 159 | "ext": "v0", 160 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 161 | "type_": "diagnostic", 162 | "body": { 163 | "v0": { 164 | "topics": [ 165 | { 166 | "symbol": "log" 167 | } 168 | ], 169 | "data": { 170 | "vec": [ 171 | { 172 | "string": "count: {}" 173 | }, 174 | { 175 | "u32": 0 176 | } 177 | ] 178 | } 179 | } 180 | } 181 | }, 182 | "failed_call": false 183 | }, 184 | { 185 | "event": { 186 | "ext": "v0", 187 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 188 | "type_": "diagnostic", 189 | "body": { 190 | "v0": { 191 | "topics": [ 192 | { 193 | "symbol": "fn_return" 194 | }, 195 | { 196 | "symbol": "increment" 197 | } 198 | ], 199 | "data": "void" 200 | } 201 | } 202 | }, 203 | "failed_call": false 204 | }, 205 | { 206 | "event": { 207 | "ext": "v0", 208 | "contract_id": null, 209 | "type_": "diagnostic", 210 | "body": { 211 | "v0": { 212 | "topics": [ 213 | { 214 | "symbol": "fn_call" 215 | }, 216 | { 217 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 218 | }, 219 | { 220 | "symbol": "get_counter" 221 | } 222 | ], 223 | "data": "void" 224 | } 225 | } 226 | }, 227 | "failed_call": false 228 | }, 229 | { 230 | "event": { 231 | "ext": "v0", 232 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 233 | "type_": "diagnostic", 234 | "body": { 235 | "v0": { 236 | "topics": [ 237 | { 238 | "symbol": "fn_return" 239 | }, 240 | { 241 | "symbol": "get_counter" 242 | } 243 | ], 244 | "data": { 245 | "u32": 1 246 | } 247 | } 248 | } 249 | }, 250 | "failed_call": false 251 | } 252 | ] 253 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/increment/test_snapshots/test/test.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [], 9 | [] 10 | ], 11 | "ledger": { 12 | "protocol_version": 20, 13 | "sequence_number": 0, 14 | "timestamp": 0, 15 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 16 | "base_reserve": 0, 17 | "min_persistent_entry_ttl": 4096, 18 | "min_temp_entry_ttl": 16, 19 | "max_entry_ttl": 6312000, 20 | "ledger_entries": [ 21 | [ 22 | { 23 | "contract_data": { 24 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 25 | "key": "ledger_key_contract_instance", 26 | "durability": "persistent" 27 | } 28 | }, 29 | [ 30 | { 31 | "last_modified_ledger_seq": 0, 32 | "data": { 33 | "contract_data": { 34 | "ext": "v0", 35 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 36 | "key": "ledger_key_contract_instance", 37 | "durability": "persistent", 38 | "val": { 39 | "contract_instance": { 40 | "executable": { 41 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 42 | }, 43 | "storage": [ 44 | { 45 | "key": { 46 | "symbol": "COUNTER" 47 | }, 48 | "val": { 49 | "u32": 3 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | }, 57 | "ext": "v0" 58 | }, 59 | 4095 60 | ] 61 | ], 62 | [ 63 | { 64 | "contract_code": { 65 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 66 | } 67 | }, 68 | [ 69 | { 70 | "last_modified_ledger_seq": 0, 71 | "data": { 72 | "contract_code": { 73 | "ext": "v0", 74 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 75 | "code": "" 76 | } 77 | }, 78 | "ext": "v0" 79 | }, 80 | 4095 81 | ] 82 | ] 83 | ] 84 | }, 85 | "events": [ 86 | { 87 | "event": { 88 | "ext": "v0", 89 | "contract_id": null, 90 | "type_": "diagnostic", 91 | "body": { 92 | "v0": { 93 | "topics": [ 94 | { 95 | "symbol": "fn_call" 96 | }, 97 | { 98 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 99 | }, 100 | { 101 | "symbol": "increment" 102 | } 103 | ], 104 | "data": "void" 105 | } 106 | } 107 | }, 108 | "failed_call": false 109 | }, 110 | { 111 | "event": { 112 | "ext": "v0", 113 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 114 | "type_": "diagnostic", 115 | "body": { 116 | "v0": { 117 | "topics": [ 118 | { 119 | "symbol": "log" 120 | } 121 | ], 122 | "data": { 123 | "vec": [ 124 | { 125 | "string": "count: {}" 126 | }, 127 | { 128 | "u32": 0 129 | } 130 | ] 131 | } 132 | } 133 | } 134 | }, 135 | "failed_call": false 136 | }, 137 | { 138 | "event": { 139 | "ext": "v0", 140 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 141 | "type_": "diagnostic", 142 | "body": { 143 | "v0": { 144 | "topics": [ 145 | { 146 | "symbol": "fn_return" 147 | }, 148 | { 149 | "symbol": "increment" 150 | } 151 | ], 152 | "data": { 153 | "u32": 1 154 | } 155 | } 156 | } 157 | }, 158 | "failed_call": false 159 | }, 160 | { 161 | "event": { 162 | "ext": "v0", 163 | "contract_id": null, 164 | "type_": "diagnostic", 165 | "body": { 166 | "v0": { 167 | "topics": [ 168 | { 169 | "symbol": "fn_call" 170 | }, 171 | { 172 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 173 | }, 174 | { 175 | "symbol": "increment" 176 | } 177 | ], 178 | "data": "void" 179 | } 180 | } 181 | }, 182 | "failed_call": false 183 | }, 184 | { 185 | "event": { 186 | "ext": "v0", 187 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 188 | "type_": "diagnostic", 189 | "body": { 190 | "v0": { 191 | "topics": [ 192 | { 193 | "symbol": "log" 194 | } 195 | ], 196 | "data": { 197 | "vec": [ 198 | { 199 | "string": "count: {}" 200 | }, 201 | { 202 | "u32": 1 203 | } 204 | ] 205 | } 206 | } 207 | } 208 | }, 209 | "failed_call": false 210 | }, 211 | { 212 | "event": { 213 | "ext": "v0", 214 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 215 | "type_": "diagnostic", 216 | "body": { 217 | "v0": { 218 | "topics": [ 219 | { 220 | "symbol": "fn_return" 221 | }, 222 | { 223 | "symbol": "increment" 224 | } 225 | ], 226 | "data": { 227 | "u32": 2 228 | } 229 | } 230 | } 231 | }, 232 | "failed_call": false 233 | }, 234 | { 235 | "event": { 236 | "ext": "v0", 237 | "contract_id": null, 238 | "type_": "diagnostic", 239 | "body": { 240 | "v0": { 241 | "topics": [ 242 | { 243 | "symbol": "fn_call" 244 | }, 245 | { 246 | "bytes": "0000000000000000000000000000000000000000000000000000000000000001" 247 | }, 248 | { 249 | "symbol": "increment" 250 | } 251 | ], 252 | "data": "void" 253 | } 254 | } 255 | }, 256 | "failed_call": false 257 | }, 258 | { 259 | "event": { 260 | "ext": "v0", 261 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 262 | "type_": "diagnostic", 263 | "body": { 264 | "v0": { 265 | "topics": [ 266 | { 267 | "symbol": "log" 268 | } 269 | ], 270 | "data": { 271 | "vec": [ 272 | { 273 | "string": "count: {}" 274 | }, 275 | { 276 | "u32": 2 277 | } 278 | ] 279 | } 280 | } 281 | } 282 | }, 283 | "failed_call": false 284 | }, 285 | { 286 | "event": { 287 | "ext": "v0", 288 | "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", 289 | "type_": "diagnostic", 290 | "body": { 291 | "v0": { 292 | "topics": [ 293 | { 294 | "symbol": "fn_return" 295 | }, 296 | { 297 | "symbol": "increment" 298 | } 299 | ], 300 | "data": { 301 | "u32": 3 302 | } 303 | } 304 | } 305 | }, 306 | "failed_call": false 307 | } 308 | ] 309 | } -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/task_manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "task-manager" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | doctest = false 10 | 11 | [dependencies] 12 | soroban-sdk = { workspace = true } 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { workspace = true, features = ["testutils"] } 16 | 17 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/task_manager/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{ 4 | contract, contracterror, contractimpl, contracttype, map, symbol_short, Env, Map, Symbol, Vec, 5 | }; 6 | 7 | const TASKS: Symbol = symbol_short!("TASKS"); 8 | const TTL_THRESHOLD: u32 = 1000; 9 | const TTL_EXTEND_TO: u32 = 5000; 10 | 11 | #[contracterror] 12 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 13 | #[repr(u32)] 14 | pub enum Error { 15 | ReadyTwice = 1, 16 | NotFound = 2, 17 | } 18 | 19 | #[contracttype] 20 | #[derive(Clone, Debug, Eq, PartialEq)] 21 | pub struct Task { 22 | pub id: u32, 23 | pub name: Symbol, 24 | pub done: bool, 25 | } 26 | 27 | impl Default for Task { 28 | fn default() -> Task { 29 | Task { 30 | id: 0, 31 | name: symbol_short!("task"), 32 | done: false, 33 | } 34 | } 35 | } 36 | 37 | pub trait CRUD { 38 | fn add_task(env: Env, name: Symbol) -> u32; 39 | 40 | fn get_task(env: Env, id: u32) -> Option; 41 | fn get_all_tasks(env: Env) -> Vec; 42 | 43 | fn complete_task(env: Env, id: u32) -> Result; 44 | 45 | fn delete_task(env: Env, id: u32) -> Result; 46 | } 47 | 48 | #[contract] 49 | struct Manager; 50 | 51 | #[contractimpl] 52 | impl CRUD for Manager { 53 | fn add_task(env: Env, name: Symbol) -> u32 { 54 | let mut tasks: Map = env.storage().instance().get(&TASKS).unwrap_or(map![&env,]); 55 | 56 | let new_id = tasks.len() as u32 + 1; 57 | let task = Task { 58 | id: new_id, 59 | name, 60 | done: false, 61 | }; 62 | 63 | tasks.set(task.id, task); 64 | 65 | env.storage().instance().set(&TASKS, &tasks); 66 | // emit event 67 | 68 | env.storage() 69 | .instance() 70 | .extend_ttl(TTL_THRESHOLD, TTL_EXTEND_TO); 71 | 72 | new_id 73 | } 74 | 75 | fn get_task(env: Env, id: u32) -> Option { 76 | env.storage() 77 | .instance() 78 | .extend_ttl(TTL_THRESHOLD, TTL_EXTEND_TO); 79 | env.storage() 80 | .instance() 81 | .get::>(&TASKS) 82 | .unwrap_or(map![&env,]) 83 | .get(id) 84 | } 85 | 86 | fn get_all_tasks(env: Env) -> Vec { 87 | env.storage() 88 | .instance() 89 | .extend_ttl(TTL_THRESHOLD, TTL_EXTEND_TO); 90 | env.storage() 91 | .instance() 92 | .get::>(&TASKS) 93 | .unwrap_or(map![&env,]) 94 | .values() 95 | } 96 | 97 | fn complete_task(env: Env, id: u32) -> Result { 98 | env.storage() 99 | .instance() 100 | .extend_ttl(TTL_THRESHOLD, TTL_EXTEND_TO); 101 | let mut tasks = env 102 | .storage() 103 | .instance() 104 | .get::>(&TASKS) 105 | .unwrap_or(map![&env,]); 106 | if let Some(mut task) = tasks.get(id) { 107 | if task.done { 108 | return Err(Error::ReadyTwice); 109 | } 110 | task.done = true; 111 | tasks.set(id, task); 112 | env.storage().instance().set(&TASKS, &tasks); 113 | Ok(true) 114 | } else { 115 | Err(Error::NotFound) 116 | } 117 | } 118 | 119 | fn delete_task(env: Env, id: u32) -> Result { 120 | env.storage() 121 | .instance() 122 | .extend_ttl(TTL_THRESHOLD, TTL_EXTEND_TO); 123 | let mut tasks = env 124 | .storage() 125 | .instance() 126 | .get::>(&TASKS) 127 | .unwrap_or(map![&env,]); 128 | if tasks.contains_key(id) { 129 | tasks.remove(id); 130 | env.storage().instance().set(&TASKS, &tasks); 131 | Ok(true) 132 | } else { 133 | Err(Error::NotFound) 134 | } 135 | } 136 | } 137 | 138 | #[cfg(test)] 139 | mod test { 140 | use super::*; 141 | 142 | #[test] 143 | fn empty_tasks_in_init() { 144 | let env = Env::default(); 145 | let contract_id = env.register_contract(None, Manager); 146 | let client = ManagerClient::new(&env, &contract_id); 147 | 148 | let tasks: Vec = client.get_all_tasks(); 149 | assert_eq!(tasks.is_empty(), true); 150 | } 151 | 152 | #[test] 153 | fn add_task() { 154 | let env = Env::default(); 155 | let contract_id = env.register_contract(None, Manager); 156 | let client = ManagerClient::new(&env, &contract_id); 157 | 158 | client.add_task(&symbol_short!("task1")); 159 | client.add_task(&symbol_short!("task2")); 160 | client.add_task(&symbol_short!("task3")); 161 | client.add_task(&symbol_short!("task4")); 162 | 163 | let tasks: Vec = client.get_all_tasks(); 164 | assert_eq!(tasks.len(), 4); 165 | assert_eq!(tasks.get(0).unwrap().name, symbol_short!("task1")); 166 | assert_eq!(tasks.get(1).unwrap().name, symbol_short!("task2")); 167 | assert_eq!(tasks.get(2).unwrap().name, symbol_short!("task3")); 168 | assert_eq!(tasks.get(3).unwrap().name, symbol_short!("task4")); 169 | } 170 | 171 | #[test] 172 | fn get_task() { 173 | let env = Env::default(); 174 | let contract_id = env.register_contract(None, Manager); 175 | let client = ManagerClient::new(&env, &contract_id); 176 | 177 | client.add_task(&symbol_short!("task1")); 178 | 179 | let task = client.get_task(&1).unwrap_or_default(); 180 | assert_eq!(task.name, symbol_short!("task1")); 181 | assert_eq!(task.done, false); 182 | } 183 | 184 | #[test] 185 | fn complete_task() { 186 | let env = Env::default(); 187 | let contract_id = env.register_contract(None, Manager); 188 | let client = ManagerClient::new(&env, &contract_id); 189 | 190 | client.add_task(&symbol_short!("task1")); 191 | client.complete_task(&1); 192 | 193 | let task = client.get_task(&1).unwrap_or_default(); 194 | assert_eq!(task.name, symbol_short!("task1")); 195 | assert_eq!(task.done, true); 196 | 197 | client.complete_task(&1); 198 | } 199 | 200 | #[test] 201 | fn delete_task() { 202 | let env = Env::default(); 203 | let contract_id = env.register_contract(None, Manager); 204 | let client = ManagerClient::new(&env, &contract_id); 205 | 206 | client.add_task(&symbol_short!("task1")); 207 | client.delete_task(&1); 208 | 209 | let task = client.get_task(&1); 210 | assert_eq!(task.is_none(), true); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /aula04/soroban-smartcontracts/contracts/task_manager/src/test.rs: -------------------------------------------------------------------------------- 1 | // Task Manager Test 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /aula05/.gitignore: -------------------------------------------------------------------------------- 1 | # Rust's output directory 2 | target 3 | 4 | # Local Soroban settings 5 | .soroban 6 | -------------------------------------------------------------------------------- /aula05/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "contracts/*", 5 | ] 6 | 7 | [workspace.dependencies] 8 | soroban-sdk = "20.3.2" 9 | 10 | [profile.release] 11 | opt-level = "z" 12 | overflow-checks = true 13 | debug = 0 14 | strip = "symbols" 15 | debug-assertions = false 16 | panic = "abort" 17 | codegen-units = 1 18 | lto = true 19 | 20 | # For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile 21 | [profile.release-with-logs] 22 | inherits = "release" 23 | debug-assertions = true 24 | -------------------------------------------------------------------------------- /aula05/README.md: -------------------------------------------------------------------------------- 1 | # Soroban 102 2 | 3 | ## make alias 4 | 5 | ```bash 6 | # ~/.zshrc 7 | # ~/.bashrc 8 | 9 | alias ska="soroban keys address " 10 | alias skl="soroban keys ls " 11 | alias scd="soroban contract deploy " 12 | alias sci="soroban contract invoke " 13 | ``` 14 | 15 | ## Deploy contract 16 | 17 | ```bash 18 | scd \ 19 | --wasm target/wasm32-unknown-unknown/release/token.wasm \ 20 | --source bob \ 21 | --network local 22 | ``` 23 | 24 | ## Get balance 25 | 26 | ```bash 27 | sci \ 28 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 29 | --source bob \ 30 | --network local \ 31 | -- \ 32 | balance \ 33 | --id $(ska bob) 34 | ``` 35 | 36 | ## Initialization of contract 37 | 38 | ```bash 39 | sci \ 40 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 41 | --source bob \ 42 | --network local \ 43 | -- \ 44 | initialize --admin $(ska bob) --decimal 2 --name RealDigital --symbol DREX 45 | ``` 46 | 47 | ## Get admin of contract 48 | 49 | ```bash 50 | sci \ 51 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 52 | --source bob \ 53 | --network local \ 54 | -- \ 55 | get_admin 56 | ``` 57 | 58 | ## Mint _DREX_ for `alice` 59 | 60 | ```bash 61 | sci \ 62 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 63 | --source bob \ 64 | --network local \ 65 | -- \ 66 | mint --to $(ska alice) --amount 100 67 | ``` 68 | 69 | ## Transfer from `alice` to `bob` 70 | 71 | ```bash 72 | sci \ 73 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 74 | --source alice \ 75 | --network local \ 76 | -- \ 77 | transfer \ 78 | --from $(ska alice) \ 79 | --to $(ska bob) \ 80 | --amount 100 81 | ``` 82 | 83 | ## Approve from `alice` to `bob` 84 | 85 | ```bash 86 | sci \ 87 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 88 | --source alice \ 89 | --network local \ 90 | -- \ 91 | approve \ 92 | --from $(ska alice) \ 93 | --to $(ska bob) \ 94 | --amount 100 95 | ``` 96 | 97 | ## TransferFrom `bob` spend `alice`'s money 98 | 99 | ```bash 100 | sci \ 101 | --id CCIFKHKLPDAIITTUNSNLBKE4EIWLSR4JY2YTIJXACJWXPBEMUKTU6WTP \ 102 | --source bob \ 103 | --network local \ 104 | -- \ 105 | trasfer_from \ 106 | --from $(ska alice) \ 107 | --to $(ska bob) \ 108 | --amount 100 109 | ``` 110 | -------------------------------------------------------------------------------- /aula05/contracts/token/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "token" 3 | description = "Soroban standard token contract" 4 | version = "0.1.0" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | soroban-token-sdk = { version = "20.3.1" } 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { workspace = true, features = ["testutils"] } 16 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/admin.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{Address, Env}; 2 | 3 | use crate::storage_types::DataKey; 4 | 5 | pub fn has_administrator(e: &Env) -> bool { 6 | let key = DataKey::Admin; 7 | e.storage().instance().has(&key) 8 | } 9 | 10 | pub fn read_administrator(e: &Env) -> Address { 11 | let key = DataKey::Admin; 12 | let admin = e.storage().instance().get(&key); 13 | if admin.is_none() { 14 | panic!("No administrator set") 15 | } 16 | 17 | admin.unwrap() 18 | } 19 | 20 | pub fn write_administrator(e: &Env, id: &Address) { 21 | let key = DataKey::Admin; 22 | e.storage().instance().set(&key, id); 23 | } 24 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/allowance.rs: -------------------------------------------------------------------------------- 1 | use crate::storage_types::{AllowanceDataKey, AllowanceValue, DataKey}; 2 | use soroban_sdk::{Address, Env}; 3 | 4 | pub fn read_allowance(e: &Env, from: Address, spender: Address) -> AllowanceValue { 5 | let key = DataKey::Allowance(AllowanceDataKey { from, spender }); 6 | if let Some(allowance) = e.storage().temporary().get::<_, AllowanceValue>(&key) { 7 | if allowance.expiration_ledger < e.ledger().sequence() { 8 | AllowanceValue { 9 | amount: 0, 10 | expiration_ledger: allowance.expiration_ledger, 11 | } 12 | } else { 13 | allowance 14 | } 15 | } else { 16 | AllowanceValue { 17 | amount: 0, 18 | expiration_ledger: 0, 19 | } 20 | } 21 | } 22 | 23 | pub fn write_allowance( 24 | e: &Env, 25 | from: Address, 26 | spender: Address, 27 | amount: i128, 28 | expiration_ledger: u32, 29 | ) { 30 | let allowance = AllowanceValue { 31 | amount, 32 | expiration_ledger, 33 | }; 34 | 35 | if amount > 0 && expiration_ledger < e.ledger().sequence() { 36 | panic!("expiration_ledger is less than ledger seq when amount > 0") 37 | } 38 | 39 | let key = DataKey::Allowance(AllowanceDataKey { from, spender }); 40 | e.storage().temporary().set(&key.clone(), &allowance); 41 | 42 | if amount > 0 { 43 | let live_for = expiration_ledger 44 | .checked_sub(e.ledger().sequence()) 45 | .unwrap(); 46 | 47 | e.storage().temporary().extend_ttl(&key, live_for, live_for) 48 | } 49 | } 50 | 51 | pub fn spend_allowance(e: &Env, from: Address, spender: Address, amount: i128) { 52 | let allowance = read_allowance(e, from.clone(), spender.clone()); 53 | if allowance.amount < amount { 54 | panic!("insufficient allowance"); 55 | } 56 | if amount > 0 { 57 | write_allowance( 58 | e, 59 | from, 60 | spender, 61 | allowance.amount - amount, 62 | allowance.expiration_ledger, 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/balance.rs: -------------------------------------------------------------------------------- 1 | use crate::storage_types::{DataKey, BALANCE_BUMP_AMOUNT, BALANCE_LIFETIME_THRESHOLD}; 2 | use soroban_sdk::{Address, Env}; 3 | 4 | pub fn read_balance(e: &Env, addr: Address) -> i128 { 5 | let key = DataKey::Balance(addr); 6 | if let Some(balance) = e.storage().persistent().get::(&key) { 7 | e.storage() 8 | .persistent() 9 | .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); 10 | balance 11 | } else { 12 | 0 13 | } 14 | } 15 | 16 | fn write_balance(e: &Env, addr: Address, amount: i128) { 17 | let key = DataKey::Balance(addr); 18 | e.storage().persistent().set(&key, &amount); 19 | e.storage() 20 | .persistent() 21 | .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); 22 | } 23 | 24 | pub fn receive_balance(e: &Env, addr: Address, amount: i128) { 25 | let balance = read_balance(e, addr.clone()); 26 | write_balance(e, addr, balance + amount); 27 | } 28 | 29 | pub fn spend_balance(e: &Env, addr: Address, amount: i128) { 30 | let balance = read_balance(e, addr.clone()); 31 | if balance < amount { 32 | panic!("insufficient balance"); 33 | } 34 | write_balance(e, addr, balance - amount); 35 | } 36 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! This contract demonstrates a sample implementation of the Soroban token 2 | //! interface. 3 | use crate::admin::{has_administrator, read_administrator, write_administrator}; 4 | use crate::allowance::{read_allowance, spend_allowance, write_allowance}; 5 | use crate::balance::{read_balance, receive_balance, spend_balance}; 6 | use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; 7 | #[cfg(test)] 8 | use crate::storage_types::{AllowanceDataKey, AllowanceValue, DataKey}; 9 | use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; 10 | use soroban_sdk::token::{self, Interface as _}; 11 | use soroban_sdk::{contract, contractimpl, Address, Env, String}; 12 | use soroban_token_sdk::metadata::TokenMetadata; 13 | use soroban_token_sdk::TokenUtils; 14 | 15 | fn check_nonnegative_amount(amount: i128) { 16 | if amount < 0 { 17 | panic!("negative amount is not allowed: {}", amount) 18 | } 19 | } 20 | 21 | #[contract] 22 | pub struct Token; 23 | 24 | #[contractimpl] 25 | impl Token { 26 | pub fn get_admin(e: Env) -> Address { 27 | let admin = read_administrator(&e); 28 | admin 29 | } 30 | 31 | pub fn initialize(e: Env, admin: Address, decimal: u32, name: String, symbol: String) { 32 | if has_administrator(&e) { 33 | panic!("already initialized") 34 | } 35 | write_administrator(&e, &admin); 36 | if decimal > 18 { 37 | panic!("Decimal must not be greater than 18"); 38 | } 39 | 40 | write_metadata( 41 | &e, 42 | TokenMetadata { 43 | decimal, 44 | name, 45 | symbol, 46 | }, 47 | ) 48 | } 49 | 50 | pub fn mint(e: Env, to: Address, amount: i128) { 51 | check_nonnegative_amount(amount); 52 | let admin = read_administrator(&e); 53 | admin.require_auth(); 54 | 55 | e.storage() 56 | .instance() 57 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 58 | 59 | receive_balance(&e, to.clone(), amount); 60 | TokenUtils::new(&e).events().mint(admin, to, amount); 61 | } 62 | 63 | pub fn set_admin(e: Env, new_admin: Address) { 64 | let admin = read_administrator(&e); 65 | admin.require_auth(); 66 | 67 | e.storage() 68 | .instance() 69 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 70 | 71 | write_administrator(&e, &new_admin); 72 | TokenUtils::new(&e).events().set_admin(admin, new_admin); 73 | } 74 | 75 | #[cfg(test)] 76 | pub fn get_allowance(e: Env, from: Address, spender: Address) -> Option { 77 | let key = DataKey::Allowance(AllowanceDataKey { from, spender }); 78 | let allowance = e.storage().temporary().get::<_, AllowanceValue>(&key); 79 | allowance 80 | } 81 | } 82 | 83 | #[contractimpl] 84 | impl token::Interface for Token { 85 | fn allowance(e: Env, from: Address, spender: Address) -> i128 { 86 | e.storage() 87 | .instance() 88 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 89 | read_allowance(&e, from, spender).amount 90 | } 91 | 92 | fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32) { 93 | from.require_auth(); 94 | 95 | check_nonnegative_amount(amount); 96 | 97 | e.storage() 98 | .instance() 99 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 100 | 101 | write_allowance(&e, from.clone(), spender.clone(), amount, expiration_ledger); 102 | TokenUtils::new(&e) 103 | .events() 104 | .approve(from, spender, amount, expiration_ledger); 105 | } 106 | 107 | fn balance(e: Env, id: Address) -> i128 { 108 | e.storage() 109 | .instance() 110 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 111 | read_balance(&e, id) 112 | } 113 | 114 | fn transfer(e: Env, from: Address, to: Address, amount: i128) { 115 | from.require_auth(); 116 | 117 | check_nonnegative_amount(amount); 118 | 119 | e.storage() 120 | .instance() 121 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 122 | 123 | spend_balance(&e, from.clone(), amount); 124 | receive_balance(&e, to.clone(), amount); 125 | TokenUtils::new(&e).events().transfer(from, to, amount); 126 | } 127 | 128 | fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128) { 129 | spender.require_auth(); 130 | 131 | check_nonnegative_amount(amount); 132 | 133 | e.storage() 134 | .instance() 135 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 136 | 137 | spend_allowance(&e, from.clone(), spender, amount); 138 | spend_balance(&e, from.clone(), amount); 139 | receive_balance(&e, to.clone(), amount); 140 | TokenUtils::new(&e).events().transfer(from, to, amount) 141 | } 142 | 143 | fn burn(e: Env, from: Address, amount: i128) { 144 | from.require_auth(); 145 | 146 | check_nonnegative_amount(amount); 147 | 148 | e.storage() 149 | .instance() 150 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 151 | 152 | spend_balance(&e, from.clone(), amount); 153 | TokenUtils::new(&e).events().burn(from, amount); 154 | } 155 | 156 | fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { 157 | spender.require_auth(); 158 | 159 | check_nonnegative_amount(amount); 160 | 161 | e.storage() 162 | .instance() 163 | .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); 164 | 165 | spend_allowance(&e, from.clone(), spender, amount); 166 | spend_balance(&e, from.clone(), amount); 167 | TokenUtils::new(&e).events().burn(from, amount) 168 | } 169 | 170 | fn decimals(e: Env) -> u32 { 171 | read_decimal(&e) 172 | } 173 | 174 | fn name(e: Env) -> String { 175 | read_name(&e) 176 | } 177 | 178 | fn symbol(e: Env) -> String { 179 | read_symbol(&e) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | mod admin; 4 | mod allowance; 5 | mod balance; 6 | mod contract; 7 | mod metadata; 8 | mod storage_types; 9 | mod test; 10 | 11 | pub use crate::contract::TokenClient; 12 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/metadata.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{Env, String}; 2 | use soroban_token_sdk::{metadata::TokenMetadata, TokenUtils}; 3 | 4 | pub fn read_decimal(e: &Env) -> u32 { 5 | let util = TokenUtils::new(e); 6 | util.metadata().get_metadata().decimal 7 | } 8 | 9 | pub fn read_name(e: &Env) -> String { 10 | let util = TokenUtils::new(e); 11 | util.metadata().get_metadata().name 12 | } 13 | 14 | pub fn read_symbol(e: &Env) -> String { 15 | let util = TokenUtils::new(e); 16 | util.metadata().get_metadata().symbol 17 | } 18 | 19 | pub fn write_metadata(e: &Env, metadata: TokenMetadata) { 20 | let util = TokenUtils::new(e); 21 | util.metadata().set_metadata(&metadata); 22 | } 23 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/storage_types.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{contracttype, Address}; 2 | 3 | pub(crate) const DAY_IN_LEDGERS: u32 = 17280; 4 | pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; 5 | pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; 6 | 7 | pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 8 | pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; 9 | 10 | #[derive(Clone)] 11 | #[contracttype] 12 | pub struct AllowanceDataKey { 13 | pub from: Address, 14 | pub spender: Address, 15 | } 16 | 17 | #[contracttype] 18 | pub struct AllowanceValue { 19 | pub amount: i128, 20 | pub expiration_ledger: u32, 21 | } 22 | 23 | #[derive(Clone)] 24 | #[contracttype] 25 | pub enum DataKey { 26 | Allowance(AllowanceDataKey), 27 | Balance(Address), 28 | State(Address), 29 | Admin, 30 | } 31 | -------------------------------------------------------------------------------- /aula05/contracts/token/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | extern crate std; 3 | 4 | use crate::{contract::Token, TokenClient}; 5 | use soroban_sdk::{ 6 | symbol_short, 7 | testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, 8 | Address, Env, IntoVal, Symbol, 9 | }; 10 | 11 | fn create_token<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { 12 | let token = TokenClient::new(e, &e.register_contract(None, Token {})); 13 | token.initialize(admin, &7, &"name".into_val(e), &"symbol".into_val(e)); 14 | token 15 | } 16 | 17 | #[test] 18 | fn test() { 19 | let e = Env::default(); 20 | e.mock_all_auths(); 21 | 22 | let admin1 = Address::generate(&e); 23 | let admin2 = Address::generate(&e); 24 | 25 | let user1 = Address::generate(&e); 26 | let user2 = Address::generate(&e); 27 | let user3 = Address::generate(&e); 28 | 29 | let token = create_token(&e, &admin1); 30 | 31 | token.mint(&user1, &1000); 32 | assert_eq!( 33 | e.auths(), 34 | std::vec![( 35 | admin1.clone(), 36 | AuthorizedInvocation { 37 | function: AuthorizedFunction::Contract(( 38 | token.address.clone(), 39 | symbol_short!("mint"), 40 | (&user1, 1000_i128).into_val(&e), 41 | )), 42 | sub_invocations: std::vec![] 43 | } 44 | )] 45 | ); 46 | assert_eq!(token.balance(&user1), 1000); 47 | 48 | token.approve(&user2, &user3, &500, &200); 49 | assert_eq!( 50 | e.auths(), 51 | std::vec![( 52 | user2.clone(), 53 | AuthorizedInvocation { 54 | function: AuthorizedFunction::Contract(( 55 | token.address.clone(), 56 | symbol_short!("approve"), 57 | (&user2, &user3, 500_i128, 200_u32).into_val(&e), 58 | )), 59 | sub_invocations: std::vec![] 60 | } 61 | )] 62 | ); 63 | assert_eq!(token.allowance(&user2, &user3), 500); 64 | 65 | token.transfer(&user1, &user2, &600); 66 | assert_eq!( 67 | e.auths(), 68 | std::vec![( 69 | user1.clone(), 70 | AuthorizedInvocation { 71 | function: AuthorizedFunction::Contract(( 72 | token.address.clone(), 73 | symbol_short!("transfer"), 74 | (&user1, &user2, 600_i128).into_val(&e), 75 | )), 76 | sub_invocations: std::vec![] 77 | } 78 | )] 79 | ); 80 | assert_eq!(token.balance(&user1), 400); 81 | assert_eq!(token.balance(&user2), 600); 82 | 83 | token.transfer_from(&user3, &user2, &user1, &400); 84 | assert_eq!( 85 | e.auths(), 86 | std::vec![( 87 | user3.clone(), 88 | AuthorizedInvocation { 89 | function: AuthorizedFunction::Contract(( 90 | token.address.clone(), 91 | Symbol::new(&e, "transfer_from"), 92 | (&user3, &user2, &user1, 400_i128).into_val(&e), 93 | )), 94 | sub_invocations: std::vec![] 95 | } 96 | )] 97 | ); 98 | assert_eq!(token.balance(&user1), 800); 99 | assert_eq!(token.balance(&user2), 200); 100 | 101 | token.transfer(&user1, &user3, &300); 102 | assert_eq!(token.balance(&user1), 500); 103 | assert_eq!(token.balance(&user3), 300); 104 | 105 | token.set_admin(&admin2); 106 | assert_eq!( 107 | e.auths(), 108 | std::vec![( 109 | admin1.clone(), 110 | AuthorizedInvocation { 111 | function: AuthorizedFunction::Contract(( 112 | token.address.clone(), 113 | symbol_short!("set_admin"), 114 | (&admin2,).into_val(&e), 115 | )), 116 | sub_invocations: std::vec![] 117 | } 118 | )] 119 | ); 120 | 121 | // Increase to 500 122 | token.approve(&user2, &user3, &500, &200); 123 | assert_eq!(token.allowance(&user2, &user3), 500); 124 | token.approve(&user2, &user3, &0, &200); 125 | assert_eq!( 126 | e.auths(), 127 | std::vec![( 128 | user2.clone(), 129 | AuthorizedInvocation { 130 | function: AuthorizedFunction::Contract(( 131 | token.address.clone(), 132 | symbol_short!("approve"), 133 | (&user2, &user3, 0_i128, 200_u32).into_val(&e), 134 | )), 135 | sub_invocations: std::vec![] 136 | } 137 | )] 138 | ); 139 | assert_eq!(token.allowance(&user2, &user3), 0); 140 | } 141 | 142 | #[test] 143 | fn test_burn() { 144 | let e = Env::default(); 145 | e.mock_all_auths(); 146 | 147 | let admin = Address::generate(&e); 148 | let user1 = Address::generate(&e); 149 | let user2 = Address::generate(&e); 150 | let token = create_token(&e, &admin); 151 | 152 | token.mint(&user1, &1000); 153 | assert_eq!(token.balance(&user1), 1000); 154 | 155 | token.approve(&user1, &user2, &500, &200); 156 | assert_eq!(token.allowance(&user1, &user2), 500); 157 | 158 | token.burn_from(&user2, &user1, &500); 159 | assert_eq!( 160 | e.auths(), 161 | std::vec![( 162 | user2.clone(), 163 | AuthorizedInvocation { 164 | function: AuthorizedFunction::Contract(( 165 | token.address.clone(), 166 | symbol_short!("burn_from"), 167 | (&user2, &user1, 500_i128).into_val(&e), 168 | )), 169 | sub_invocations: std::vec![] 170 | } 171 | )] 172 | ); 173 | 174 | assert_eq!(token.allowance(&user1, &user2), 0); 175 | assert_eq!(token.balance(&user1), 500); 176 | assert_eq!(token.balance(&user2), 0); 177 | 178 | token.burn(&user1, &500); 179 | assert_eq!( 180 | e.auths(), 181 | std::vec![( 182 | user1.clone(), 183 | AuthorizedInvocation { 184 | function: AuthorizedFunction::Contract(( 185 | token.address.clone(), 186 | symbol_short!("burn"), 187 | (&user1, 500_i128).into_val(&e), 188 | )), 189 | sub_invocations: std::vec![] 190 | } 191 | )] 192 | ); 193 | 194 | assert_eq!(token.balance(&user1), 0); 195 | assert_eq!(token.balance(&user2), 0); 196 | } 197 | 198 | #[test] 199 | #[should_panic(expected = "insufficient balance")] 200 | fn transfer_insufficient_balance() { 201 | let e = Env::default(); 202 | e.mock_all_auths(); 203 | 204 | let admin = Address::generate(&e); 205 | let user1 = Address::generate(&e); 206 | let user2 = Address::generate(&e); 207 | let token = create_token(&e, &admin); 208 | 209 | token.mint(&user1, &1000); 210 | assert_eq!(token.balance(&user1), 1000); 211 | 212 | token.transfer(&user1, &user2, &1001); 213 | } 214 | 215 | #[test] 216 | #[should_panic(expected = "insufficient allowance")] 217 | fn transfer_from_insufficient_allowance() { 218 | let e = Env::default(); 219 | e.mock_all_auths(); 220 | 221 | let admin = Address::generate(&e); 222 | let user1 = Address::generate(&e); 223 | let user2 = Address::generate(&e); 224 | let user3 = Address::generate(&e); 225 | let token = create_token(&e, &admin); 226 | 227 | token.mint(&user1, &1000); 228 | assert_eq!(token.balance(&user1), 1000); 229 | 230 | token.approve(&user1, &user3, &100, &200); 231 | assert_eq!(token.allowance(&user1, &user3), 100); 232 | 233 | token.transfer_from(&user3, &user1, &user2, &101); 234 | } 235 | 236 | #[test] 237 | #[should_panic(expected = "already initialized")] 238 | fn initialize_already_initialized() { 239 | let e = Env::default(); 240 | let admin = Address::generate(&e); 241 | let token = create_token(&e, &admin); 242 | 243 | token.initialize(&admin, &10, &"name".into_val(&e), &"symbol".into_val(&e)); 244 | } 245 | 246 | #[test] 247 | #[should_panic(expected = "Decimal must not be greater than 18")] 248 | fn decimal_is_over_eighteen() { 249 | let e = Env::default(); 250 | let admin = Address::generate(&e); 251 | let token = TokenClient::new(&e, &e.register_contract(None, Token {})); 252 | token.initialize(&admin, &19, &"name".into_val(&e), &"symbol".into_val(&e)); 253 | } 254 | 255 | #[test] 256 | fn test_zero_allowance() { 257 | // Here we test that transfer_from with a 0 amount does not create an empty allowance 258 | let e = Env::default(); 259 | e.mock_all_auths(); 260 | 261 | let admin = Address::generate(&e); 262 | let spender = Address::generate(&e); 263 | let from = Address::generate(&e); 264 | let token = create_token(&e, &admin); 265 | 266 | token.transfer_from(&spender, &from, &spender, &0); 267 | assert!(token.get_allowance(&from, &spender).is_none()); 268 | } 269 | 270 | #[test] 271 | fn test_get_admin() { 272 | // Here we test that transfer_from with a 0 amount does not create an empty allowance 273 | let e = Env::default(); 274 | e.mock_all_auths(); 275 | 276 | let admin = Address::generate(&e); 277 | let spender = Address::generate(&e); 278 | let from = Address::generate(&e); 279 | let token = create_token(&e, &admin); 280 | 281 | token.transfer_from(&spender, &from, &spender, &0); 282 | assert!(token.get_allowance(&from, &spender).is_none()); 283 | } 284 | --------------------------------------------------------------------------------