Skip to main content

RotatingSigner

Struct RotatingSigner 

Source
pub struct RotatingSigner { /* private fields */ }
Expand description

A signer that rotates through multiple keys for the same account.

This solves the nonce collision problem for high-throughput applications. Each call to key() atomically claims the next key in round-robin order.

§Use Case

NEAR uses per-key nonces. When sending concurrent transactions with a single key, they can collide on nonce values. By rotating through multiple keys, each concurrent transaction uses a different key with its own nonce sequence.

§Loading Keys from Other Sources

Keys can be loaded from any storage backend (file, keyring, env) via from_signers():

let rotating = RotatingSigner::from_signers(vec![
    FileSigner::from_file("keys/bot-key-0.json", "bot.testnet")?.into_inner(),
    FileSigner::from_file("keys/bot-key-1.json", "bot.testnet")?.into_inner(),
])?;

§Sequential Sends

Use into_per_key_signers() to split into per-key InMemorySigner instances for building sequential send queues. See the sequential_sends example.

§Example

use near_kit::{RotatingSigner, SecretKey, Signer};

let keys = vec![
    SecretKey::generate_ed25519(),
    SecretKey::generate_ed25519(),
    SecretKey::generate_ed25519(),
];

let signer = RotatingSigner::new("bot.testnet", keys).unwrap();

// Each key() call atomically claims the next key in sequence
let key1 = signer.key();
let key2 = signer.key();
let key3 = signer.key();
// key4 wraps back to the first key
let key4 = signer.key();

Implementations§

Source§

impl RotatingSigner

Source

pub fn new( account_id: impl AsRef<str>, keys: Vec<SecretKey>, ) -> Result<Self, Error>

Create a rotating signer with multiple keys.

§Arguments
  • account_id - The NEAR account ID
  • keys - Vector of secret keys (must not be empty)
§Errors

Returns an error if:

  • The account ID cannot be parsed
  • The keys vector is empty
Source

pub fn from_signers(signers: Vec<InMemorySigner>) -> Result<Self, Error>

Create a rotating signer from InMemorySigner instances.

This accepts signers loaded from any source (keyring, file, env, etc.) via their into_inner() method. All signers must share the same account ID.

§Example
use near_kit::{RotatingSigner, FileSigner};

// Load keys from separate credential files for the same account
let signers = vec![
    FileSigner::from_file("keys/bot-key-0.json", "bot.testnet")?.into_inner(),
    FileSigner::from_file("keys/bot-key-1.json", "bot.testnet")?.into_inner(),
];
let rotating = RotatingSigner::from_signers(signers)?;
Source

pub fn from_key_strings( account_id: impl AsRef<str>, keys: &[impl AsRef<str>], ) -> Result<Self, Error>

Create a rotating signer from key strings.

§Arguments
  • account_id - The NEAR account ID
  • keys - Slice of secret keys in string format (e.g., “ed25519:…”)
Source

pub fn key_count(&self) -> usize

Get the number of keys in rotation.

Source

pub fn public_keys(&self) -> Vec<PublicKey>

Get all public keys.

Source

pub fn signing_keys(&self) -> Vec<SigningKey>

Get all signing keys without advancing the rotation counter.

Useful for building per-key data structures like sequential send queues. Unlike key(), calling this does not affect the rotation.

Source

pub fn into_per_key_signers(self) -> Vec<InMemorySigner>

Split into per-key InMemorySigner instances.

Each signer uses a single key from the rotation pool, allowing independent send ordering per key. The global nonce manager automatically tracks nonces per (account_id, public_key), so per-key signers coordinate correctly without extra setup.

§Example
use near_kit::{RotatingSigner, SecretKey};

let keys = vec![SecretKey::generate_ed25519(), SecretKey::generate_ed25519()];
let rotating = RotatingSigner::new("bot.testnet", keys).unwrap();

// Create per-key signers for sequential queue workers
let per_key: Vec<_> = rotating.into_per_key_signers();
assert_eq!(per_key.len(), 2);

Trait Implementations§

Source§

impl Debug for RotatingSigner

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Signer for RotatingSigner

Source§

fn account_id(&self) -> &AccountId

The account this signer signs for.
Source§

fn key(&self) -> SigningKey

Get a key for signing. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more