Skip to content

Commit

Permalink
[Proposal] Separating action with transaction builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
ckshitij committed May 21, 2024
1 parent 4676451 commit 90482a7
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 13 deletions.
52 changes: 44 additions & 8 deletions near-accounts/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use near_primitives::views::{FinalExecutionOutcomeView, QueryRequest, TxExecutio
use near_providers::types::query::{QueryResponseKind, RpcQueryResponse};
use near_providers::types::transactions::RpcTransactionResponse;
use near_providers::Provider;
use near_transactions::TransactionBuilder;
use near_transactions::{ActionBuilder, TransactionBuilder};

use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::ops::{Add, Mul, Sub};
Expand Down Expand Up @@ -183,6 +184,34 @@ impl Account {
Ok(signed_tx)
}

async fn signed_transaction(
&self,
actions: &mut ActionBuilder,
receiver_id: &AccountId,
) -> Result<SignedTransaction, Box<dyn std::error::Error>> {
// Fetch the current nonce for the signer account and latest block hash
let nonce = self
.fetch_nonce(&self.account_id, &self.signer.public_key())
.await?;

//Block hash
let block_reference = BlockReference::Finality(Finality::Final);
let block = self.provider.block(block_reference).await?;
let block_hash = block.header.hash;

// Use TransactionBuilder to construct the transaction
let signed_tx = TransactionBuilder::new(
self.account_id.clone(),
self.signer.public_key(),
receiver_id.clone(),
nonce + 1,
block_hash,
)
.set_action(actions.clone_builder())
.sign_transaction(&*self.signer);
Ok(signed_tx)
}

/// Fetches the current nonce for an account's access key.
///
/// # Arguments
Expand Down Expand Up @@ -234,13 +263,20 @@ impl Account {
amount: Balance,
) -> Result<FinalExecutionOutcomeView, Box<dyn std::error::Error>> {
// Use TransactionBuilder to construct the transaction
let signed_tx = &self
.get_transaction_builder(new_account_id)
.await?
.create_account()
.transfer(amount)
.add_key(public_key, full_access_key())
.sign_transaction(&*self.signer); // Sign the transaction
let mut builder = ActionBuilder::new();
let actions = builder
.set_create_account()
.set_transfer(amount)
.set_add_key(public_key.clone(), full_access_key());
// .clone_builder();

// let signed_tx = &self
// .get_transaction_builder(new_account_id)
// .await?
// .set_action(actions)
// .sign_transaction(&*self.signer); // Sign the transaction

let signed_tx = &self.signed_transaction(actions, new_account_id).await?;

// Send the transaction
let transaction_result = self.provider.send_transaction(signed_tx.clone()).await?;
Expand Down
108 changes: 108 additions & 0 deletions near-transactions/src/action_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//! Provides a builder pattern for constructing NEAR blockchain transactions.
//!
//! The `ActionBuilder` facilitates the addition for various actions on the NEAR blockchain,
//! such as transferring tokens, creating accounts, deploying contracts, and more. It abstracts away the complexities
//! involved in constructing transactions manually, ensuring that transactions are built correctly before submission.
//!
//! With `ActionBuilder`, users can dynamically add actions to a transaction and chain these actions together
//! in a fluent API style. After constructing a transaction, it can be signed with a `Signer` implementation,
//! producing a `SignedTransaction` that is ready for submission to the NEAR blockchain.
//!
//! This module aims to simplify transaction creation and enhance developer experience by providing a clear and concise
//! way to interact with the NEAR blockchain programmatically.
use near_crypto::PublicKey;
use near_primitives::{
account::AccessKey,
action::StakeAction,
transaction::{
Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction,
DeployContractAction, FunctionCallAction, TransferAction,
},
types::{AccountId, Balance, Gas},
};

// Define the ActionBuilder struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActionBuilder {
actions: Vec<Action>,
}

impl ActionBuilder {
// Constructor for ActionBuilder
pub fn new() -> Self {
Self {
actions: Vec::new(),
}
}

// Methods to add various actions to the builder
pub fn set_create_account(&mut self) -> &mut Self {
self.actions
.push(Action::CreateAccount(CreateAccountAction {}));
self
}

pub fn set_deploy_contract(&mut self, code: &[u8]) -> &mut Self {
self.actions
.push(Action::DeployContract(DeployContractAction {
code: code.to_vec(),
}));
self
}

pub fn function_call(
&mut self,
method_name: String,
args: Vec<u8>,
gas: Gas,
deposit: Balance,
) -> &mut Self {
self.actions
.push(Action::FunctionCall(Box::new(FunctionCallAction {
method_name,
args,
gas,
deposit,
})));
self
}

pub fn set_transfer(&mut self, deposit: Balance) -> &mut Self {
self.actions
.push(Action::Transfer(TransferAction { deposit }));
self
}

pub fn set_stake(&mut self, stake: Balance, public_key: PublicKey) -> &mut Self {
self.actions
.push(Action::Stake(Box::new(StakeAction { stake, public_key })));
self
}

pub fn set_add_key(&mut self, public_key: PublicKey, access_key: AccessKey) -> &mut Self {
self.actions.push(Action::AddKey(Box::new(AddKeyAction {
public_key,
access_key,
})));
self
}

pub fn set_delete_key(&mut self, public_key: PublicKey) -> &mut Self {
self.actions
.push(Action::DeleteKey(Box::new(DeleteKeyAction { public_key })));
self
}

pub fn set_delete_account(&mut self, beneficiary_id: AccountId) -> &mut Self {
self.actions
.push(Action::DeleteAccount(DeleteAccountAction {
beneficiary_id,
}));
self
}

// Build method to finalize and retrieve the actions
pub fn clone_builder(&self) -> Vec<Action> {
self.clone().actions
}
}
2 changes: 2 additions & 0 deletions near-transactions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
//! This crate aims to simplify transaction creation and management, making it more accessible for developers to
//! interact with the NEAR blockchain programmatically.

pub use crate::action_builder::ActionBuilder;
pub use crate::transaction_builder::TransactionBuilder;

mod action_builder;
mod transaction_builder;
18 changes: 13 additions & 5 deletions near-transactions/src/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ impl TransactionBuilder {
SignedTransaction::new(signature, self.transaction.clone())
}

// Finalize and return the built Transaction
pub fn build(self) -> Transaction {
self.transaction
}

pub fn set_action(&mut self, actions: Vec<Action>) -> &mut Self {
self.transaction.actions = actions;
self
}

// We can remove the below function
// since all handling different actions

/// Methods to add CreateAccount action directly to the Transaction's actions vector
pub fn create_account(&mut self) -> &mut Self {
self.transaction
Expand Down Expand Up @@ -129,9 +142,4 @@ impl TransactionBuilder {
}));
self
}

// Finalize and return the built Transaction
pub fn build(self) -> Transaction {
self.transaction
}
}

0 comments on commit 90482a7

Please sign in to comment.