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
impl RotatingSigner
Sourcepub fn from_signers(signers: Vec<InMemorySigner>) -> Result<Self, Error>
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)?;Sourcepub fn from_key_strings(
account_id: impl AsRef<str>,
keys: &[impl AsRef<str>],
) -> Result<Self, Error>
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 IDkeys- Slice of secret keys in string format (e.g., “ed25519:…”)
Sourcepub fn public_keys(&self) -> Vec<PublicKey>
pub fn public_keys(&self) -> Vec<PublicKey>
Get all public keys.
Sourcepub fn signing_keys(&self) -> Vec<SigningKey>
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.
Sourcepub fn into_per_key_signers(self) -> Vec<InMemorySigner>
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);