< Summary

Information
Class: EF.Blockchain.Server.Endpoints.WalletEndpoints
Assembly: EF.Blockchain.Server
File(s): C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Server\Endpoints\WalletEndpoints.cs
Line coverage
32%
Covered lines: 32
Uncovered lines: 66
Coverable lines: 98
Total lines: 167
Line coverage: 32.6%
Branch coverage
0%
Covered branches: 0
Total branches: 16
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapWalletEndpoints(...)100%11100%
MapWalletEndpoints(...)100%11100%
GetWalletInfo(...)100%11100%
GetWalletInfo(...)100%11100%
CreateWallet()0%210140%
RecoverWallet(...)100%210%

File(s)

C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Server\Endpoints\WalletEndpoints.cs

#LineLine coverage
 1using System.Threading.Tasks;
 2using EF.Blockchain.Domain;
 3using EF.Blockchain.Server.Dtos;
 4using EF.Blockchain.Server.Mappers;
 5using Microsoft.AspNetCore.Mvc;
 6
 7namespace EF.Blockchain.Server.Endpoints;
 8
 9/// <summary>
 10/// Provides endpoints to query wallet information.
 11/// </summary>
 12public static class WalletEndpoints
 13{
 14    /// <summary>
 15    /// Maps wallet-related endpoints.
 16    /// </summary>
 5617    /// <param name="app">The endpoint route builder.</param>
 5618    public static void MapWalletEndpoints(this IEndpointRouteBuilder app)
 11219    {
 11220        app.MapGet("/wallets/{walletAddress}", GetWalletInfo)
 11221           .WithName("GetWalletInfo")
 11222           .WithTags("Wallet")
 11223           .WithSummary("Get wallet balance, fee, and UTXOs")
 11224           .WithDescription("Returns balance, transaction fee, and unspent transaction outputs (UTXOs) for a wallet.")
 11225           .Produces<WalletDto>(StatusCodes.Status200OK)
 5626           .WithOpenApi();
 27
 5628        app.MapPost("/wallets", CreateWallet)
 5629           .WithName("CreateWallet")
 5630           .WithTags("Wallet")
 5631           .WithSummary("Create a new wallet")
 5632           .WithDescription("Generates a new wallet with public key, private key, and mnemonic phrase.")
 5633           .Produces<WalletDto>(StatusCodes.Status201Created)
 5634           .WithOpenApi();
 35
 6036        app.MapPost("/wallets/recover", RecoverWallet)
 6037           .WithName("RecoverWallet")
 6038           .WithTags("Wallet")
 5639           .WithSummary("Recover an existing wallet")
 6040           .WithDescription("Recovers a wallet using private key or mnemonic phrase.")
 5641           .Produces<WalletDto>(StatusCodes.Status200OK)
 6042           .Produces(StatusCodes.Status400BadRequest)
 6043           .WithOpenApi();
 5644    }
 45
 46    /// <summary>
 47    /// Handles the GET /wallets/{walletAddress} endpoint.
 48    /// </summary>
 49    /// <param name="walletAddress">Wallet public address.</param>
 50    /// <param name="blockchain">Injected blockchain instance.</param>
 51    /// <returns>Wallet details including balance, fee, and UTXOs.</returns>
 52    private static WalletDto GetWalletInfo(
 53        [FromRoute] string walletAddress,
 54        [FromServices] Domain.Blockchain blockchain)
 455    {
 456        int balance = blockchain.GetBalance(walletAddress);
 457        int fee = blockchain.GetFeePerTx();
 58
 459        var utxo = blockchain.GetUtxo(walletAddress);
 60
 461        return WalletMapper.ToDto(balance, fee, utxo);
 462    }
 63
 64    /// <summary>
 65    /// Handles the POST /wallets endpoint.
 66    /// </summary>
 67    private static async Task<IResult> CreateWallet([FromBody] WalletDto walletDto,
 68        IConfiguration config,
 69        [FromServices] Domain.Blockchain blockchain)
 070    {
 71        try
 072        {
 073            var newWallet = new Wallet();
 074            var amountFaucet = 10;
 75
 076            var miner = config["Blockchain:MinerWallet:PrivateKey"]
 077                ?? Environment.GetEnvironmentVariable("BLOCKCHAIN_MINER")
 078                ?? "default-miner";
 79
 080            var minerWallet = new Wallet(miner);
 81
 082            var fromWalletBalance = blockchain.GetBalance(minerWallet.PublicKey ?? "");
 083            var fee = blockchain.GetFeePerTx();
 084            var utxos = blockchain.GetUtxo(minerWallet.PublicKey ?? "");
 85
 086            var txInputs = utxos
 087                .Select(TransactionInput.FromTxo)
 088                .ToList();
 89
 090            txInputs.ForEach(input => input.Sign(minerWallet.PrivateKey ?? ""));
 91
 092            var txOutputs = new List<TransactionOutput>
 093            {
 094                new TransactionOutput(
 095                    toAddress: newWallet.PublicKey ?? "",
 096                    amount: amountFaucet
 097                )
 098            };
 99
 0100            var remaining = fromWalletBalance - amountFaucet - fee;
 0101            if (remaining > 0)
 0102            {
 0103                txOutputs.Add(new TransactionOutput(
 0104                    toAddress: minerWallet.PublicKey ?? "",
 0105                    amount: remaining
 0106                ));
 0107            }
 108
 0109            var faucetTransaction = new Transaction(
 0110                type: TransactionType.REGULAR,
 0111                timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
 0112                txInputs: txInputs,
 0113                txOutputs: txOutputs
 0114            );
 115
 0116            blockchain.AddTransaction(faucetTransaction);
 117
 0118            await Task.Delay(2000);
 119
 0120            walletDto.PublicKey = newWallet.PublicKey;
 0121            walletDto.PrivateKey = newWallet.PrivateKey;
 0122            walletDto.Balance = amountFaucet;
 123
 0124            return Results.Created($"/wallets/{walletDto.PublicKey}", walletDto);
 125        }
 0126        catch (Exception ex)
 0127        {
 0128            return Results.Problem(
 0129                title: "Wallet Creation Failed",
 0130                detail: ex.Message,
 0131                statusCode: StatusCodes.Status500InternalServerError
 0132            );
 133        }
 0134    }
 135
 136    /// <summary>
 137    /// Handles the POST /wallets/recover endpoint.
 138    /// </summary>
 139    /// <param name="walletDto">The wallet recovery request.</param>
 140    /// <param name="blockchain">Injected blockchain instance.</param>
 141    /// <returns>The recovered wallet information.</returns>
 142    private static IResult RecoverWallet(
 143        [FromBody] WalletDto walletDto,
 144        [FromServices] Domain.Blockchain blockchain)
 0145    {
 146        try
 0147        {
 0148            Domain.Wallet recoveredWallet = new Domain.Wallet(walletDto.PrivateKey);
 149
 0150            int balance = blockchain.GetBalance(recoveredWallet.PublicKey);
 151
 0152            walletDto.PublicKey = recoveredWallet.PublicKey;
 0153            walletDto.PrivateKey = recoveredWallet.PrivateKey;
 0154            walletDto.Balance = balance;
 155
 0156            return Results.Ok(walletDto);
 157        }
 0158        catch (Exception ex)
 0159        {
 0160            return Results.Problem(
 0161                title: "Wallet Recovery Failed",
 0162                detail: ex.Message,
 0163                statusCode: StatusCodes.Status500InternalServerError
 0164            );
 165        }
 0166    }
 167}