1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
mod impls;

use std::fmt;
use std::sync::Arc;

use crate::network::builder::NetworkBuilder;
use crate::network::{Betanet, Custom, Mainnet, Sandbox, Testnet};
use crate::types::GasHook;
use crate::{Network, Result};

/// The `Worker` type allows us to interact with any NEAR related networks, such
/// as mainnet and testnet. This controls where the environment the worker is
/// running on top of it. Refer to this for all network related actions such as
/// deploying a contract, or interacting with transactions.
pub struct Worker<T: ?Sized> {
    pub(crate) workspace: Arc<T>,
    pub(crate) tx_callbacks: Vec<GasHook>,
}

impl<T> Worker<T>
where
    T: Network,
{
    pub(crate) fn new(network: T) -> Self {
        Self {
            workspace: Arc::new(network),
            tx_callbacks: vec![],
        }
    }
}

impl<T: Network + 'static> Worker<T> {
    pub(crate) fn coerce(self) -> Worker<dyn Network> {
        Worker {
            workspace: self.workspace,
            tx_callbacks: self.tx_callbacks,
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for Worker<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Worker")
            .field("workspace", &self.workspace)
            .finish()
    }
}

/// Spin up a new sandbox instance, and grab a [`Worker`] that interacts with it.
pub fn sandbox<'a>() -> NetworkBuilder<'a, Sandbox> {
    NetworkBuilder::new("sandbox")
}

/// Spin up a new sandbox instance, and grab a [`Worker`] that interacts with it.
pub async fn sandbox_with_version<'a>(version: &str) -> Result<Worker<Sandbox>> {
    let network_builder = NetworkBuilder::new("sandbox");
    let network = Sandbox::from_builder_with_version(network_builder, version).await?;
    Ok(Worker::new(network))
}

/// Connect to the [testnet](https://explorer.testnet.near.org/) network, and grab
/// a [`Worker`] that can interact with it.
pub fn testnet<'a>() -> NetworkBuilder<'a, Testnet> {
    NetworkBuilder::new("testnet")
}

/// Connect to the [testnet archival](https://near-nodes.io/intro/node-types#archival-node)
/// network, and grab a [`Worker`] that can interact with it.
pub fn testnet_archival<'a>() -> NetworkBuilder<'a, Testnet> {
    NetworkBuilder::new("testnet-archival").rpc_addr(crate::network::testnet::ARCHIVAL_URL)
}

/// Connect to the [mainnet](https://explorer.near.org/) network, and grab
/// a [`Worker`] that can interact with it.
pub fn mainnet<'a>() -> NetworkBuilder<'a, Mainnet> {
    NetworkBuilder::new("mainnet")
}

/// Connect to the [mainnet archival](https://near-nodes.io/intro/node-types#archival-node)
/// network, and grab a [`Worker`] that can interact with it.
pub fn mainnet_archival<'a>() -> NetworkBuilder<'a, Mainnet> {
    NetworkBuilder::new("mainnet-archival").rpc_addr(crate::network::mainnet::ARCHIVAL_URL)
}

/// Connect to the betanet network, and grab a [`Worker`] that can interact with it.
pub fn betanet<'a>() -> NetworkBuilder<'a, Betanet> {
    NetworkBuilder::new("betanet")
}

/// Connect to a custom network, and grab a [`Worker`] that can interact with it.
///
/// Note: the burden of ensuring the methods that are able to be called are left up to the user.
pub fn custom<'a>(rpc_url: &str) -> NetworkBuilder<'a, Custom> {
    NetworkBuilder::new("custom").rpc_addr(rpc_url)
}

/// Run a locally scoped task where a [`sandbox`] instanced [`Worker`] is supplied.
pub async fn with_sandbox<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Sandbox>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(sandbox().await?).await)
}

/// Run a locally scoped task where a [`testnet`] instanced [`Worker`] is supplied.
pub async fn with_testnet<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Testnet>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(testnet().await?).await)
}

/// Run a locally scoped task where a [`testnet_archival`] instanced [`Worker`] is supplied.
pub async fn with_testnet_archival<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Testnet>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(testnet_archival().await?).await)
}

/// Run a locally scoped task where a [`mainnet`] instanced [`Worker`] is supplied.
pub async fn with_mainnet<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Mainnet>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(mainnet().await?).await)
}

/// Run a locally scoped task where a [`mainnet_archival`] instanced [`Worker`] is supplied.
pub async fn with_mainnet_archival<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Mainnet>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(mainnet_archival().await?).await)
}

/// Run a locally scoped task where a [`betanet`] instanced [`Worker`] is supplied.
pub async fn with_betanet<F, T>(task: F) -> Result<T::Output>
where
    F: Fn(Worker<Betanet>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(betanet().await?).await)
}

#[allow(dead_code)]
pub async fn with_custom<F, T>(task: F, rpc_url: &str) -> Result<T::Output>
where
    F: Fn(Worker<Custom>) -> T + Send + Sync,
    T: core::future::Future + Send,
{
    Ok(task(custom(rpc_url).await?).await)
}