Graffle Flow SDK

The Graffle Flow SDK is a C# SDK that abstracts away the gRPC calls to interact with the Flow blockchain. https://github.com/Graffle/flow-c-sharp-graffle-sdk

Create client:

var flowClientFactory = new FlowClientFactory(nodeName);
var flowClient = flowClientFactory.CreateFlowClient();

Get latest block:

var latestBlock = flowClient.GetLatestBlockAsync();

Get latest sealed block:

var latestBlock = await flowClient.GetLatestBlockAsync(true);

Search a block range for a specific event:

    var eventId = "A.c1e4f4f4c4257510.Market.MomentPurchased";
    ulong startBlock = 22037959;
    ulong endBlock = 22037961;
    var eventsResponse = await flowClient.GetEventsForHeightRangeAsync(eventId, startBlock, endBlock);

Execute script at block id:

    var latestBlockResponse = await this.flowClient.GetLatestBlockAsync(true);

    var helloWorldScript = @"
        pub fun main(): String {
            return ""Hello World""
        }               
    ";
    
    var scriptBytes = Encoding.ASCII.GetBytes(helloWorldScript);
    
    var scriptResponse = await flowClient.ExecuteScriptAtBlockIdAsync(latestBlockResponse.Id.HashToByteString(), scriptBytes, new List<FlowValueType>());
    var metaDataJson = Encoding.Default.GetString(scriptResponse.Value.ToByteArray());
    var result = StringType.FromJson(metaDataJson);

Execute script at block height:

    var latestBlockResponse = await this.flowClient.GetLatestBlockAsync(true);

    var helloWorldScript = @"
        pub fun main(): String {
            return ""Hello World""
        }               
    ";
    
    var scriptBytes = Encoding.ASCII.GetBytes(helloWorldScript);
    
    var scriptResponse = await flowClient.ExecuteScriptAtBlockIdAsync(latestBlockResponse.Height, scriptBytes, new List<FlowValueType>());
    var metaDataJson = Encoding.Default.GetString(scriptResponse.Value.ToByteArray());
    var result = StringType.FromJson(metaDataJson);

Get block at height

    var blockResponse = await flowClient.GetBlockByHeightAsync(blockHeight);

Get a transaction within a block

    var block = await flowClient.GetBlockByHeightAsync(blockHeight);
    var collectionId = block.CollectionGuarantees.FirstOrDefault().CollectionId;
    var collection = await flowClient.GetCollectionById(collectionId.HashToByteString());
    var transactionId = collection.TransactionIds.FirstOrDefault();
    var transactionResult = await flowClient.GetTransactionResult(transactionId.HashToByteString());
    var transaction = await flowClient.GetTransactionAsync(transactionId.HashToByteString());  

Get account at block height

    var account = await flowClient.GetAccountAsync(addressHex, blockHeight)

Get collection by Id

    var collection = await flowClient.GetCollectionById(collectionId.HashToByteString());

Create a new account

//example given using emulator account, load real account from flow.json for working with MainNet or TestNet
    var emulatorAccount = await flowClient.GetAccountFromConfigAsync("emulator-account");

    var emulatorAccountKey = emulatorAccount.Keys[0];

    var flowAccountKey = Flow.Entities.AccountKey.GenerateRandomEcdsaKey(SignatureAlgorithm.ECDSA_P256, HashAlgorithm.SHA3_256);
    var newFlowAccountKeys = new List<Flow.Entities.AccountKey> { flowAccountKey };

    var latestBlock = await flowClient.GetLatestBlockAsync();
    var emulatorAddress = new FlowAddress(emulatorAccount.Address);

    var transaction = AccountTransactions.CreateAccount(newFlowAccountKeys, emulatorAddress);

    transaction.Payer = emulatorAddress;
    transaction.ProposalKey = new FlowProposalKey
    {
        Address = emulatorAddress,
        KeyId = emulatorAccountKey.Index,
        SequenceNumber = emulatorAccountKey.SequenceNumber
    };
    transaction.ReferenceBlockId = latestBlock.Id;

    // sign and submit the transaction
    transaction = FlowTransaction.AddEnvelopeSignature(transaction, emulatorAddress, emulatorAccountKey.Index, emulatorAccountKey.Signer);

    var response = await flowClient.SendTransactionAsync(transaction);

    // wait for seal
    var sealedResponse = await flowClient.WaitForSealAsync(response);

    var createdEvent = sealedResponse.Events.FirstOrDefault(x => x.Type == "flow.AccountCreated");

    string addressHex = createdEvent.EventComposite.Data.FirstOrDefault().Value.Substring(2);

    var address = new FlowAddress(addressHex);

    var latestBlock2 = await flowClient.GetLatestBlockAsync();
    var account = await flowClient.GetAccountAsync(addressHex, latestBlock2.Height);

    account.Keys = FlowAccountKey.UpdateFlowAccountKeys(newFlowAccountKeys.Select(x => new FlowAccountKey(x)).ToList(), account.Keys.ToList());

Send transaction

    var emulatorAccount = await flowClient.GetAccountFromConfigAsync("emulator-account");
    var emulatorAddress = new FlowAddress(emulatorAccount.Address);
    var emulatorAccountKey = emulatorAccount.Keys[0];

    var latestBlock = await flowClient.GetLatestBlockAsync();
    var transaction = new FlowTransaction
    {
        Script = new FlowScript("transaction {}"),
        ReferenceBlockId = latestBlock.Id,
        Payer = emulatorAddress,
        ProposalKey = new FlowProposalKey
        {
            Address = emulatorAddress,
            KeyId = emulatorAccountKey.Index,
            SequenceNumber = emulatorAccountKey.SequenceNumber
        }
    };

    transaction = FlowTransaction.AddEnvelopeSignature(transaction, emulatorAddress, emulatorAccountKey.Index, emulatorAccountKey.Signer);

    var response = await flowClient.SendTransactionAsync(transaction);

    // wait for seal
    var sealedResponse = await flowClient.WaitForSealAsync(response);

Last updated