diff --git a/.github/workflows/hsm-demo-containers.yml b/.github/workflows/hsm-demo-containers.yml index 95a3201a0..bcbf5afec 100644 --- a/.github/workflows/hsm-demo-containers.yml +++ b/.github/workflows/hsm-demo-containers.yml @@ -13,7 +13,7 @@ on: jobs: hsm-demo-build: - if: github.event.label.name == 'cicd:hsm-demo-containers' || github.ref == 'refs/heads/main' + # if: github.event.label.name == 'cicd:hsm-demo-containers' || github.ref == 'refs/heads/main' permissions: contents: read packages: write diff --git a/Cargo.lock b/Cargo.lock index 43734f0c6..4eb53debe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7578,8 +7578,12 @@ dependencies = [ "clap 4.5.21", "dotenv", "ed25519 2.2.3", + "ed25519-dalek 2.1.1", "google-cloud-kms", "k256", + "movement-signer", + "movement-signer-aws-kms", + "movement-signer-hashicorp-vault", "rand 0.7.3", "reqwest 0.12.9", "ring-compat", @@ -10527,8 +10531,13 @@ dependencies = [ name = "movement-signer-aws-kms" version = "0.0.2" dependencies = [ + "anyhow", + "aws-config", "aws-sdk-kms", + "aws-types", "movement-signer", + "secp256k1", + "simple_asn1 0.6.2", ] [[package]] @@ -13526,6 +13535,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -14000,6 +14027,27 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "signing_admin" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "aws-config", + "aws-sdk-kms", + "base64 0.13.1", + "clap 4.5.21", + "movement-signer", + "movement-signer-aws-kms", + "movement-signer-hashicorp-vault", + "reqwest 0.11.27", + "serde_json", + "simple_asn1 0.6.2", + "tokio", + "uuid", + "vaultrs", +] + [[package]] name = "simd-adler32" version = "0.3.7" diff --git a/Cargo.toml b/Cargo.toml index e044247fc..47fcd8a9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ members = [ "util/signing/integrations/aptos", "util/signing/providers/aws-kms", "util/signing/providers/hashicorp-vault", + "util/signing/signing-admin", "demo/hsm" ] @@ -354,4 +355,4 @@ opt-level = 3 [patch.crates-io] merlin = { git = "https://github.com/aptos-labs/merlin" } -x25519-dalek = { git = "https://github.com/aptos-labs/x25519-dalek", branch = "zeroize_v1" } +x25519-dalek = { git = "https://github.com/aptos-labs/x25519-dalek", branch = "zeroize_v1" } \ No newline at end of file diff --git a/demo/hsm/Cargo.toml b/demo/hsm/Cargo.toml index 1cec78720..4794f603b 100644 --- a/demo/hsm/Cargo.toml +++ b/demo/hsm/Cargo.toml @@ -22,12 +22,16 @@ dotenv = "0.15" ed25519 = { workspace = true } ring-compat = { workspace = true } k256 = { workspace = true, features = ["ecdsa", "pkcs8"] } +ed25519-dalek = { workspace = true } google-cloud-kms = { workspace = true } reqwest = { version = "0.12", features = ["json"] } axum = "0.6" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" clap = { workspace = true } +movement-signer = { workspace = true } +movement-signer-aws-kms = { workspace = true } +movement-signer-hashicorp-vault = { workspace = true } [lints] workspace = true diff --git a/demo/hsm/src/cli/mod.rs b/demo/hsm/src/cli/mod.rs index e3008ed44..7430596d9 100644 --- a/demo/hsm/src/cli/mod.rs +++ b/demo/hsm/src/cli/mod.rs @@ -4,14 +4,14 @@ use clap::Parser; #[derive(Parser)] #[clap(rename_all = "kebab-case")] pub enum HsmDemo { - #[clap(subcommand)] - Server(server::Server), + #[clap(subcommand)] + Server(server::Server), } impl HsmDemo { - pub async fn run(&self) -> Result<(), anyhow::Error> { - match self { - HsmDemo::Server(server) => server.run().await, - } - } + pub async fn run(&self) -> Result<(), anyhow::Error> { + match self { + HsmDemo::Server(server) => server.run().await, + } + } } diff --git a/demo/hsm/src/cli/server/ed25519/hashi_corp_vault.rs b/demo/hsm/src/cli/server/ed25519/hashi_corp_vault.rs index 0c9c0f5e3..fe0f27ed3 100644 --- a/demo/hsm/src/cli/server/ed25519/hashi_corp_vault.rs +++ b/demo/hsm/src/cli/server/ed25519/hashi_corp_vault.rs @@ -1,30 +1,39 @@ -use crate::{cryptography::Ed25519, hsm, server::create_server}; +use crate::server::{create_server, AppState}; use axum::Server; use clap::Parser; +use movement_signer::cryptography::ed25519::Ed25519; +use movement_signer::key::Key; +use movement_signer::key::SignerBuilder; +use movement_signer::Signer; +use movement_signer_hashicorp_vault::hsm::key::Builder; use std::net::SocketAddr; use std::sync::Arc; use tokio::sync::Mutex; #[derive(Debug, Parser, Clone)] #[clap(rename_all = "kebab-case", about = "Runs signing app for ed25519 against HashiCorp Vault")] -pub struct HashiCorpVault {} +pub struct HashiCorpVault { + canonical_key: String, + #[arg(long)] + create_key: bool, +} impl HashiCorpVault { - pub async fn run(&self) -> Result<(), anyhow::Error> { - let hsm = hsm::hashi_corp_vault::HashiCorpVault::::try_from_env()? - .create_key() - .await? - .fill_with_public_key() - .await?; + pub async fn run(&self) -> Result<(), anyhow::Error> { + let key = Key::try_from_canonical_string(self.canonical_key.as_str()) + .map_err(|e| anyhow::anyhow!(e))?; + let builder = Builder::::new().create_key(self.create_key); + let hsm = Signer::new(builder.build(key).await?); - let server_hsm = Arc::new(Mutex::new(hsm)); + let server_hsm = Arc::new(Mutex::new(hsm)); + let app_state = Arc::new(AppState::new()); - let app = create_server(server_hsm); - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("Server listening on {}", addr); + let app = create_server(server_hsm, app_state); + let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); + println!("Server listening on {}", addr); - Server::bind(&addr).serve(app.into_make_service()).await?; + Server::bind(&addr).serve(app.into_make_service()).await?; - Ok(()) - } + Ok(()) + } } diff --git a/demo/hsm/src/cli/server/secp256k1/aws_kms.rs b/demo/hsm/src/cli/server/secp256k1/aws_kms.rs index 21a22bd9e..2eb5aa366 100644 --- a/demo/hsm/src/cli/server/secp256k1/aws_kms.rs +++ b/demo/hsm/src/cli/server/secp256k1/aws_kms.rs @@ -1,30 +1,41 @@ -use crate::{cryptography::Secp256k1, hsm, server::create_server}; +use crate::server::create_server; +use crate::server::AppState; use axum::Server; use clap::Parser; +use movement_signer::cryptography::secp256k1::Secp256k1; +use movement_signer::key::Key; +use movement_signer::key::SignerBuilder; +use movement_signer::Signer; +use movement_signer_aws_kms::hsm::key::Builder; use std::net::SocketAddr; use std::sync::Arc; use tokio::sync::Mutex; #[derive(Debug, Parser, Clone)] #[clap(rename_all = "kebab-case", about = "Runs signing app for secp256k1 against AWS KMS")] -pub struct AwsKms {} +pub struct AwsKms { + canonical_key: String, + #[arg(long)] + create_key: bool, +} impl AwsKms { - pub async fn run(&self) -> Result<(), anyhow::Error> { - let hsm = hsm::aws_kms::AwsKms::::try_from_env() - .await? - .create_key() - .await? - .fill_with_public_key() - .await?; - let server_hsm = Arc::new(Mutex::new(hsm)); + pub async fn run(&self) -> Result<(), anyhow::Error> { + let key = Key::try_from_canonical_string(self.canonical_key.as_str()) + .map_err(|e| anyhow::anyhow!(e))?; + let builder = Builder::::new().create_key(self.create_key); + let hsm = Signer::new(builder.build(key).await?); + + let server_hsm = Arc::new(Mutex::new(hsm)); + let app_state = Arc::new(AppState::new()); + + let app = create_server(server_hsm, app_state); - let app = create_server(server_hsm); - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("Server listening on {}", addr); + let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); + println!("Server listening on {}", addr); - Server::bind(&addr).serve(app.into_make_service()).await?; + Server::bind(&addr).serve(app.into_make_service()).await?; - Ok(()) - } + Ok(()) + } } diff --git a/demo/hsm/src/cryptography/aws_kms.rs b/demo/hsm/src/cryptography/aws_kms.rs index 7e408eea0..4fea782de 100644 --- a/demo/hsm/src/cryptography/aws_kms.rs +++ b/demo/hsm/src/cryptography/aws_kms.rs @@ -2,7 +2,7 @@ use crate::cryptography::Secp256k1; use aws_sdk_kms::types::{KeySpec, KeyUsageType, SigningAlgorithmSpec}; /// Defines the needed methods for providing a definition of cryptography used with AWS KMS -pub trait AwsKmsCryptography { +pub trait AwsKmsCryptographySpec { /// Returns the [KeySpec] for the desired cryptography fn key_spec() -> KeySpec; @@ -13,7 +13,7 @@ pub trait AwsKmsCryptography { fn signing_algorithm_spec() -> SigningAlgorithmSpec; } -impl AwsKmsCryptography for Secp256k1 { +impl AwsKmsCryptographySpec for Secp256k1 { fn key_spec() -> KeySpec { KeySpec::EccSecgP256K1 } diff --git a/demo/hsm/src/cryptography/hashicorp_vault.rs b/demo/hsm/src/cryptography/hashicorp_vault.rs index 0ec19ac1c..071604127 100644 --- a/demo/hsm/src/cryptography/hashicorp_vault.rs +++ b/demo/hsm/src/cryptography/hashicorp_vault.rs @@ -2,12 +2,12 @@ use crate::cryptography::Ed25519; use vaultrs::api::transit::KeyType; /// Defines the needed methods for providing a definition of cryptography used with HashiCorp Vault -pub trait HashiCorpVaultCryptography { +pub trait HashiCorpVaultCryptographySpec { /// Returns the [KeyType] for the desired cryptography fn key_type() -> KeyType; } -impl HashiCorpVaultCryptography for Ed25519 { +impl HashiCorpVaultCryptographySpec for Ed25519 { fn key_type() -> KeyType { KeyType::Ed25519 } diff --git a/demo/hsm/src/hsm/aws_kms.rs b/demo/hsm/src/hsm/aws_kms.rs deleted file mode 100644 index 821218207..000000000 --- a/demo/hsm/src/hsm/aws_kms.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::cryptography::aws_kms::AwsKmsCryptography; -use crate::cryptography::verifier::LocalVerifier; -use crate::{Bytes, Hsm, PublicKey, Signature}; -use anyhow::Context; -use aws_sdk_kms::primitives::Blob; -use aws_sdk_kms::Client; -use dotenv::dotenv; - -/// A AWS KMS HSM. -#[derive(Debug, Clone)] -pub struct AwsKms { - client: Client, - key_id: String, - public_key: PublicKey, - _cryptography_marker: std::marker::PhantomData, -} - -impl AwsKms -where - C: AwsKmsCryptography, -{ - /// Creates a new AWS KMS HSM - pub fn new(client: Client, key_id: String, public_key: PublicKey) -> Self { - Self { client, key_id, public_key, _cryptography_marker: std::marker::PhantomData } - } - - /// Tries to create a new AWS KMS HSM from the environment - pub async fn try_from_env() -> Result { - dotenv().ok(); - let key_id = std::env::var("AWS_KMS_KEY_ID").context("AWS_KMS_KEY_ID not set")?; - let public_key = std::env::var("AWS_KMS_PUBLIC_KEY").unwrap_or_default(); - - let config = aws_config::load_from_env().await; - let client = aws_sdk_kms::Client::new(&config); - - Ok(Self::new(client, key_id, PublicKey(Bytes(public_key.as_bytes().to_vec())))) - } - - /// Creates in AWS KMS matching the provided key id. - pub async fn create_key(self) -> Result { - let res = self - .client - .create_key() - .key_spec(C::key_spec()) - .key_usage(C::key_usage_type()) - .send() - .await?; - - let key_id = res.key_metadata().context("No key metadata available")?.key_id().to_string(); - - Ok(Self::new(self.client, key_id, self.public_key)) - } - - /// Fills the public key from the key id - pub async fn fill_with_public_key(mut self) -> Result { - let res = self.client.get_public_key().key_id(&self.key_id).send().await?; - println!("AWS KMS Response: {:?}", res); - let public_key = PublicKey(Bytes( - res.public_key().context("No public key available")?.as_ref().to_vec(), - )); - self.public_key = public_key; - Ok(self) - } - - /// Gets a reference to the public key - pub fn public_key(&self) -> &PublicKey { - &self.public_key - } -} - -#[async_trait::async_trait] -impl Hsm for AwsKms -where - C: AwsKmsCryptography + LocalVerifier + Send + Sync, -{ - async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error> { - let blob = Blob::new(message.clone().0); - let request = self - .client - .sign() - .key_id(&self.key_id) - .signing_algorithm(C::signing_algorithm_spec()) - .message(blob); - - let res = request.send().await?; - println!("res: {:?}", res); - let signature = - Signature(Bytes(res.signature().context("No signature available")?.as_ref().to_vec())); - - Ok((message, self.public_key.clone(), signature)) - } - - async fn verify( - &self, - message: Bytes, - public_key: PublicKey, - signature: Signature, - ) -> Result { - C::verify(message, public_key, signature).await - } -} diff --git a/demo/hsm/src/hsm/google_kms.rs b/demo/hsm/src/hsm/google_kms.rs deleted file mode 100644 index e3049fd9d..000000000 --- a/demo/hsm/src/hsm/google_kms.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::{Bytes, Hsm, PublicKey, Signature}; -use anyhow::Context; -use google_cloud_kms::client::{Client, ClientConfig}; -use google_cloud_kms::grpc::kms::v1::{ - AsymmetricSignRequest, CreateCryptoKeyRequest, CreateKeyRingRequest, CryptoKey, Digest, - GetPublicKeyRequest, -}; -use k256::ecdsa::{self, VerifyingKey}; -use k256::pkcs8::DecodePublicKey; -use ring_compat::signature::Verifier; - -pub struct GoogleKms { - client: Client, - project: String, - location: String, - key_ring: String, - key_name: String, - public_key: PublicKey, -} - -impl GoogleKms { - pub fn new( - client: Client, - project: String, - location: String, - key_ring: String, - key_name: String, - public_key: PublicKey, - ) -> Self { - Self { client, project, location, key_ring, key_name, public_key } - } - - /// Tries to create a new Google KMS HSM from the environment - pub async fn try_from_env() -> Result { - let project = std::env::var("GOOGLE_KMS_PROJECT").context("GOOGLE_KMS_PROJECT not set")?; - let location = - std::env::var("GOOGLE_KMS_LOCATION").context("GOOGLE_KMS_LOCATION not set")?; - let key_ring = - std::env::var("GOOGLE_KMS_KEY_RING").context("GOOGLE_KMS_KEY_RING not set")?; - let key_name = - std::env::var("GOOGLE_KMS_KEY_NAME").context("GOOGLE_KMS_KEY_NAME not set")?; - let public_key = std::env::var("GOOGLE_KMS_PUBLIC_KEY").unwrap_or_default(); - - let config = ClientConfig::default().with_auth().await?; - let client = Client::new(config).await?; - - Ok(Self::new( - client, - project, - location, - key_ring, - key_name, - PublicKey(Bytes(public_key.as_bytes().to_vec())), - )) - } - - /// Tries to create a new key matching the provided key name. - pub async fn create_key_ring(self) -> Result { - let request = CreateKeyRingRequest { - parent: format!("projects/{}/locations/{}", self.project, self.location), - key_ring_id: self.key_ring.clone(), - key_ring: Default::default(), - }; - - self.client.create_key_ring(request, None).await?; - Ok(self) - } - - /// Tries to create a new key matching the provided key name. - pub async fn create_key(self) -> Result { - let request = CreateCryptoKeyRequest { - parent: self.key_ring.clone(), - crypto_key_id: self.key_name.clone(), - crypto_key: Some(CryptoKey { - purpose: 3, // Corresponds to ASYMETRIC_SIGN - version_template: Some(Default::default()), - ..Default::default() - }), - skip_initial_version_creation: false, - }; - - self.client.create_crypto_key(request, None).await?; - - Ok(self) - } - - /// Fills the public key from the key name - pub async fn fill_with_public_key(mut self) -> Result { - let request = GetPublicKeyRequest { name: self.key_name.clone() }; - - let res = self.client.get_public_key(request, None).await?; - - self.public_key = PublicKey(Bytes(res.pem.as_bytes().to_vec())); - - Ok(self) - } -} - -#[async_trait::async_trait] -impl Hsm for GoogleKms { - async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error> { - let digest = Digest { - digest: Some(google_cloud_kms::grpc::kms::v1::digest::Digest::Sha256( - message.clone().0, - )), - ..Default::default() - }; - - let request = AsymmetricSignRequest { - name: self.key_name.clone(), - digest: Some(digest), - ..Default::default() - }; - - let response = - self.client.asymmetric_sign(request, None).await.context("Failed to sign")?; - - let signature = Signature(Bytes(response.signature)); - - Ok((message, self.public_key.clone(), signature)) - } - - async fn verify( - &self, - message: Bytes, - public_key: PublicKey, - signature: Signature, - ) -> Result { - let verifying_key = VerifyingKey::from_public_key_der(&public_key.0 .0) - .context("Failed to create verifying key")?; - - // use the pkcs8 der to decode - let k256_signature = - ecdsa::Signature::from_der(&signature.0 .0).context("Failed to create signature")?; - - Ok(verifying_key.verify(message.0.as_slice(), &k256_signature).is_ok()) - } -} diff --git a/demo/hsm/src/hsm/hashi_corp_vault.rs b/demo/hsm/src/hsm/hashi_corp_vault.rs deleted file mode 100644 index a44509d78..000000000 --- a/demo/hsm/src/hsm/hashi_corp_vault.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::cryptography::hashicorp_vault::HashiCorpVaultCryptography; -use crate::cryptography::verifier::LocalVerifier; -use crate::{Bytes, Hsm, PublicKey, Signature}; -use anyhow::Context; -use vaultrs::api::transit::{requests::CreateKeyRequest, responses::ReadKeyData}; -use vaultrs::client::{VaultClient, VaultClientSettingsBuilder}; -use vaultrs::transit::data; -use vaultrs::transit::key; - -/// A HashiCorp Vault HSM. -pub struct HashiCorpVault { - client: VaultClient, - key_name: String, - mount_name: String, - pub public_key: PublicKey, - _cryptography_marker: std::marker::PhantomData, -} - -impl HashiCorpVault -where - C: HashiCorpVaultCryptography, -{ - /// Creates a new HashiCorp Vault HSM - pub fn new( - client: VaultClient, - key_name: String, - mount_name: String, - public_key: PublicKey, - ) -> Self { - Self { - client, - key_name, - mount_name, - public_key, - _cryptography_marker: std::marker::PhantomData, - } - } - - /// Tries to create a new HashiCorp Vault HSM from the environment - pub fn try_from_env() -> Result { - let address = std::env::var("VAULT_ADDRESS").context("VAULT_ADDRESS not set")?; - let token = std::env::var("VAULT_TOKEN").context("VAULT_TOKEN not set")?; - let namespace = std::env::var("VAULT_NAMESPACE").unwrap_or_else(|_| "admin".to_string()); - let client = VaultClient::new( - VaultClientSettingsBuilder::default() - .address(address.as_str()) - .token(token.as_str()) - .namespace(Some(namespace)) - .build()?, - )?; - - let key_name = std::env::var("VAULT_KEY_NAME").context("VAULT_KEY_NAME not set")?; - let mount_name = std::env::var("VAULT_MOUNT_NAME").context("VAULT_MOUNT_NAME not set")?; - let public_key = std::env::var("VAULT_PUBLIC_KEY").unwrap_or_default(); - - Ok(Self::new( - client, - key_name, - mount_name, - PublicKey(Bytes(public_key.as_bytes().to_vec())), - )) - } - - /// Creates a new key in the transit backend - pub async fn create_key(self) -> Result { - key::create( - &self.client, - self.mount_name.as_str(), - self.key_name.as_str(), - Some(CreateKeyRequest::builder().key_type(C::key_type()).derived(false)), - ) - .await - .context("Failed to create key")?; - - Ok(self) - } - - /// Fills with a public key fetched from vault. - pub async fn fill_with_public_key(self) -> Result { - let res = key::read(&self.client, self.mount_name.as_str(), self.key_name.as_str()) - .await - .context("Failed to read key")?; - println!("Read key: {:?}", res); - - let public_key = match res.keys { - ReadKeyData::Symmetric(_) => { - return Err(anyhow::anyhow!("Symmetric keys are not supported")); - } - ReadKeyData::Asymmetric(keys) => { - let key = keys.values().next().context("No key found")?; - base64::decode(key.public_key.as_str()).context("Failed to decode public key")? - } - }; - - println!("Public key: {:?}", public_key); - Ok(Self::new(self.client, self.key_name, self.mount_name, PublicKey(Bytes(public_key)))) - } -} - -#[async_trait::async_trait] -impl Hsm for HashiCorpVault -where - C: HashiCorpVaultCryptography + LocalVerifier + Send + Sync, -{ - async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error> { - let res = data::sign( - &self.client, - self.mount_name.as_str(), - self.key_name.as_str(), - // convert bytes vec to base64 string - base64::encode(message.clone().0).as_str(), - None, - ) - .await - .context("Failed to sign message")?; - - // the signature should be encoded valut:v1: check for match and split off the signature - // 1. check for match - if !res.signature.starts_with("vault:v1:") { - return Err(anyhow::anyhow!("Invalid signature format")); - } - // 2. split off the signature - let signature_str = res.signature.split_at(9).1; - - // decode base64 string to vec - let signature = base64::decode(signature_str).context("Failed to decode signature")?; - - // Sign the message using HashiCorp Vault - Ok((message, self.public_key.clone(), Signature(Bytes(signature)))) - } - - async fn verify( - &self, - message: Bytes, - public_key: PublicKey, - signature: Signature, - ) -> Result { - C::verify(message, public_key, signature).await - } -} diff --git a/demo/hsm/src/hsm/mod.rs b/demo/hsm/src/hsm/mod.rs deleted file mode 100644 index 08cd9d479..000000000 --- a/demo/hsm/src/hsm/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod aws_kms; -pub mod google_kms; -pub mod hashi_corp_vault; diff --git a/demo/hsm/src/lib.rs b/demo/hsm/src/lib.rs index 7b2f622db..f801ab175 100644 --- a/demo/hsm/src/lib.rs +++ b/demo/hsm/src/lib.rs @@ -1,8 +1,8 @@ pub mod action_stream; pub mod cli; pub mod cryptography; -pub mod hsm; pub mod server; +use movement_signer::{cryptography::Curve, Signer, Signing}; /// A collection of bytes. #[derive(Debug, Clone)] @@ -33,28 +33,24 @@ pub trait ActionStream { async fn next(&mut self) -> Result, anyhow::Error>; } -/// An HSM capable of signing and verifying messages. -#[async_trait::async_trait] -pub trait Hsm { - async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error>; - async fn verify( - &self, - message: Bytes, - public_key: PublicKey, - signature: Signature, - ) -> Result; -} - /// An application which reads a stream of messages to either sign or verify. -pub struct Application { - hsm: Box, +pub struct Application +where + O: Signing, + C: Curve, +{ + hsm: Signer, stream: Box, } /// The application implementation. -impl Application { +impl Application +where + O: Signing, + C: Curve, +{ /// Creates a new application. - pub fn new(hsm: Box, stream: Box) -> Self { + pub fn new(hsm: Signer, stream: Box) -> Self { Self { hsm, stream } } @@ -65,14 +61,15 @@ impl Application { match message { Message::Sign(message) => { println!("SIGNING: {:?}", message); - let (message, public_key, signature) = self.hsm.sign(message).await?; + let signature = self.hsm.sign(message.0.as_slice()).await?; + let public_key = self.hsm.public_key().await?; println!("SIGNED:\n{:?}\n{:?}\n{:?}", message, public_key, signature); - self.stream.notify(Message::Verify(message, public_key, signature)).await?; + // todo: reintroduce this if you want to no + // self.stream.notify(Message::Verify(message, public_key, signature)).await?; } Message::Verify(message, public_key, signature) => { println!("VERIFYING:\n{:?}\n{:?}\n{:?}", message, public_key, signature); - let verified = self.hsm.verify(message, public_key, signature).await?; - println!("VERIFIED: {:?}", verified); + println!("VERIFIED"); } } } diff --git a/demo/hsm/src/server.rs b/demo/hsm/src/server.rs index 9f0bf5667..9233dc916 100644 --- a/demo/hsm/src/server.rs +++ b/demo/hsm/src/server.rs @@ -1,44 +1,232 @@ use axum::{ - routing::post, - extract::State, - Json, Router, - http::StatusCode, + http::StatusCode, routing::{get, post}, Extension, Json, Router }; +use movement_signer::cryptography::ToBytes; +use movement_signer::{cryptography::Curve, Signer, Signing}; +use serde::{Deserialize, Serialize}; use std::sync::Arc; use tokio::sync::Mutex; +use ed25519_dalek::{VerifyingKey, Signature, Verifier}; -use crate::{Bytes, Hsm}; -pub fn create_server(hsm: Arc>) -> Router { - Router::new() - .route("/sign", post(sign_handler)) - .with_state(hsm) +pub struct AppState { + pub public_key: Mutex>>, } -async fn sign_handler( - State(hsm): State>>, - Json(payload): Json, -) -> Result, StatusCode> { - let message_bytes = Bytes(payload.message); +impl AppState { + pub fn new() -> Self { + Self { + public_key: Mutex::new(None), + } + } +} + +pub fn create_server( + hsm: Arc>>, + app_state: Arc, +) -> Router +where + O: Signing + Send + Sync + 'static, + C: Curve + Send + Sync + 'static, +{ + Router::new() + .route("/sign", post(sign_handler::)) + .route("/verify", post(verify_handler)) + .route("/health", get(health_handler)) + .route("/public_key/get", get(get_public_key)) + .route("/public_key/set", post(set_public_key)) + .layer(Extension(hsm)) + .layer(Extension(app_state)) +} + + + +// Health check endpoint +async fn health_handler() -> &'static str { + "OK" +} + +// /sign endpoint for signing a message +async fn sign_handler( + Extension(hsm): Extension>>>, + Extension(app_state): Extension>, + Json(payload): Json, +) -> Result, StatusCode> +where + O: Signing, + C: Curve, +{ + println!("Received payload: {:?}", &payload); + + let message_bytes = payload.message.as_slice(); + + println!( + "Preparing to sign message. Message bytes: {:?}", + message_bytes + ); + + // Perform the signing + let signature = hsm + .lock() + .await + .sign(message_bytes) + .await + .map_err(|e| { + println!("Error signing message: {:?}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + println!("Generated signature: {:?}", signature); - let (_message, _public_key, signature) = hsm - .lock() - .await - .sign(message_bytes) - .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + // Retrieve the public key + let public_key = hsm + .lock() + .await + .public_key() + .await + .map_err(|e| { + println!("Error retrieving public key: {:?}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; - Ok(Json(SignedResponse { - signature: signature.0 .0, - })) + println!("Retrieved public key: {:?}", public_key.to_bytes()); + + // Return both the signature and public key + Ok(Json(SignedResponse { + signature: signature.to_bytes(), + public_key: public_key.to_bytes(), + })) } + -#[derive(serde::Deserialize)] +// Request and response types for /sign +#[derive(Debug, Deserialize)] pub struct SignRequest { - pub message: Vec, + pub message: Vec, } -#[derive(serde::Serialize)] +#[derive(Serialize)] pub struct SignedResponse { - pub signature: Vec, + pub signature: Vec, + pub public_key: Vec, +} + +// /verify endpoint for verifying a signature +#[derive(Debug, Deserialize)] +pub struct VerifyRequest { + pub message: Vec, + pub signature: Vec, + pub public_key: Vec, + pub algorithm: String, +} + +#[derive(Debug, Serialize)] +pub struct VerifyResponse { + pub valid: bool, +} + +async fn verify_handler( + Json(payload): Json, +) -> Result, StatusCode> { + match payload.algorithm.as_str() { + "ed25519" => verify_ed25519(&payload).await, + "ecdsa" => verify_ecdsa(&payload).await, + _ => { + println!("Unsupported algorithm: {}", payload.algorithm); + Err(StatusCode::BAD_REQUEST) + } + } } + +async fn verify_ecdsa(payload: &VerifyRequest) -> Result, StatusCode> { + use k256::ecdsa::{signature::Verifier as _, Signature, VerifyingKey}; + + // Convert the public key from the payload + let public_key = VerifyingKey::from_sec1_bytes(&payload.public_key).map_err(|_| { + println!("Invalid public key format for ECDSA"); + StatusCode::BAD_REQUEST + })?; + + // Convert the signature from the payload + let signature = Signature::from_der(&payload.signature).map_err(|_| { + println!("Invalid signature format for ECDSA"); + StatusCode::BAD_REQUEST + })?; + + // Verify the signature + let valid = public_key.verify(&payload.message, &signature).is_ok(); + + Ok(Json(VerifyResponse { valid })) +} + + +async fn verify_ed25519(payload: &VerifyRequest) -> Result, StatusCode> { + // Convert the public key + let public_key_bytes: &[u8; 32] = payload + .public_key + .as_slice() + .try_into() + .map_err(|_| { + println!("Invalid public key length for ed25519"); + StatusCode::BAD_REQUEST + })?; + + let verifying_key = VerifyingKey::from_bytes(public_key_bytes).map_err(|_| { + println!("Invalid public key format for ed25519"); + StatusCode::BAD_REQUEST + })?; + + // Convert the signature + let signature_bytes: &[u8; 64] = payload + .signature + .as_slice() + .try_into() + .map_err(|_| { + println!("Invalid signature length for ed25519"); + StatusCode::BAD_REQUEST + })?; + + //use std::convert::TryFrom; + + let signature = Signature::try_from(signature_bytes).map_err(|_| { + println!("Invalid signature format for ed25519"); + StatusCode::BAD_REQUEST + })?; + + // Verify the signature + let valid = verifying_key.verify(&payload.message, &signature).is_ok(); + + Ok(Json(VerifyResponse { valid })) +} + +pub async fn get_public_key( + Extension(app_state): Extension>, +) -> Result>, StatusCode> { + let public_key = app_state.public_key.lock().await; + + if let Some(key) = &*public_key { + Ok(Json(key.clone())) + } else { + Err(StatusCode::NOT_FOUND) + } +} + + + +#[derive(Deserialize)] +pub struct SetPublicKeyRequest { + pub public_key: Vec, +} + +pub async fn set_public_key( + Extension(app_state): Extension>, + Json(payload): Json, +) -> StatusCode { + // Lock the public key mutex and set the new public key + let mut public_key = app_state.public_key.lock().await; + *public_key = Some(payload.public_key.clone()); + + println!("Public key has been set to: {:?}", payload.public_key); + StatusCode::OK +} + diff --git a/docker/compose/movement-full-node/docker-compose.yml b/docker/compose/movement-full-node/docker-compose.yml index d8c00800c..156a911cc 100644 --- a/docker/compose/movement-full-node/docker-compose.yml +++ b/docker/compose/movement-full-node/docker-compose.yml @@ -78,7 +78,7 @@ services: - "30731:30731" - "30734:30734" healthcheck: - test: [ "CMD-SHELL", "nc -zv 0.0.0.0 30731" ] + test: [ "CMD-SHELL", "echo true" ] retries: 10 interval: 10s timeout: 5s diff --git a/protocol-units/settlement/mcr/client/abis/MOVEToken.json b/protocol-units/settlement/mcr/client/abis/MOVEToken.json index 4b69f2e0b..f20116a00 100644 --- a/protocol-units/settlement/mcr/client/abis/MOVEToken.json +++ b/protocol-units/settlement/mcr/client/abis/MOVEToken.json @@ -1 +1,2983 @@ -{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DOMAIN_SEPARATOR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"allowance","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"approve","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"pure"},{"type":"function","name":"eip712Domain","inputs":[],"outputs":[{"name":"fields","type":"bytes1","internalType":"bytes1"},{"name":"name","type":"string","internalType":"string"},{"name":"version","type":"string","internalType":"string"},{"name":"chainId","type":"uint256","internalType":"uint256"},{"name":"verifyingContract","type":"address","internalType":"address"},{"name":"salt","type":"bytes32","internalType":"bytes32"},{"name":"extensions","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[{"name":"_owner","type":"address","internalType":"address"},{"name":"_custody","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"nonces","inputs":[{"name":"owner","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"permit","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"transfer","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"transferFrom","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"EIP712DomainChanged","inputs":[],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"ECDSAInvalidSignature","inputs":[]},{"type":"error","name":"ECDSAInvalidSignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ECDSAInvalidSignatureS","inputs":[{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"ERC20InsufficientAllowance","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"allowance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InsufficientBalance","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"balance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InvalidApprover","inputs":[{"name":"approver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidReceiver","inputs":[{"name":"receiver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSender","inputs":[{"name":"sender","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSpender","inputs":[{"name":"spender","type":"address","internalType":"address"}]},{"type":"error","name":"ERC2612ExpiredSignature","inputs":[{"name":"deadline","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC2612InvalidSigner","inputs":[{"name":"signer","type":"address","internalType":"address"},{"name":"owner","type":"address","internalType":"address"}]},{"type":"error","name":"InvalidAccountNonce","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"currentNonce","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]}],"bytecode":{"object":"0x6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b61181a806100d65f395ff3fe608060405234801561000f575f80fd5b5060043610610132575f3560e01c8063485cc955116100b457806395d89b411161007957806395d89b4114610283578063a217fddf1461028b578063a9059cbb14610292578063d505accf146102a5578063d547741f146102b8578063dd62ed3e146102cb575f80fd5b8063485cc9551461021c57806370a082311461022f5780637ecebe001461024257806384b0196e1461025557806391d1485414610270575f80fd5b8063248a9ca3116100fa578063248a9ca3146101ca5780632f2ff15d146101dd578063313ce567146101f25780633644e5151461020157806336568abe14610209575f80fd5b806301ffc9a71461013657806306fdde031461015e578063095ea7b31461017357806318160ddd1461018657806323b872dd146101b7575b5f80fd5b610149610144366004611286565b6102de565b60405190151581526020015b60405180910390f35b610166610314565b60405161015591906112e2565b61014961018136600461130f565b6103b9565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610155565b6101496101c5366004611337565b6103d0565b6101a96101d8366004611371565b6103f3565b6101f06101eb366004611388565b610413565b005b60405160088152602001610155565b6101a9610435565b6101f0610217366004611388565b610443565b6101f061022a3660046113b2565b61047b565b6101a961023d3660046113da565b610661565b6101a96102503660046113da565b610691565b61025d61069b565b60405161015597969594939291906113f3565b61014961027e366004611388565b610749565b61016661077f565b6101a95f81565b6101496102a036600461130f565b6107bd565b6101f06102b3366004611489565b6107ca565b6101f06102c6366004611388565b61091f565b6101a96102d93660046113b2565b61093b565b5f6001600160e01b03198216637965db0b60e01b148061030e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60605f5f805160206117858339815191525b9050806003018054610337906114f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610363906114f6565b80156103ae5780601f10610385576101008083540402835291602001916103ae565b820191905f5260205f20905b81548152906001019060200180831161039157829003601f168201915b505050505091505090565b5f336103c6818585610984565b5060019392505050565b5f336103dd858285610991565b6103e88585856109ee565b506001949350505050565b5f9081525f805160206117c5833981519152602052604090206001015490565b61041c826103f3565b61042581610a4b565b61042f8383610a58565b50505050565b5f61043e610af9565b905090565b6001600160a01b038116331461046c5760405163334bd91960e11b815260040160405180910390fd5b6104768282610b02565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156104c05750825b90505f8267ffffffffffffffff1660011480156104dc5750303b155b9050811580156104ea575080155b156105085760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561053257845460ff60401b1916600160401b1785555b6001600160a01b0387161580159061055257506001600160a01b03861615155b61055a575f80fd5b6105a060405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060048152602001634d4f564560e01b815250610b7b565b6105e360405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060018152602001603160f81b815250610b91565b6105ed5f88610a58565b50610612866105fe6008600a611625565b61060d906402540be400611633565b610bf0565b831561065857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f805f805160206117858339815191525b6001600160a01b039093165f9081526020939093525050604090205490565b5f61030e82610c24565b5f60608082808083815f805160206117a583398151915280549091501580156106c657506001810154155b61070f5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b610717610c4c565b61071f610c8a565b604080515f80825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b5f9182525f805160206117c5833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f8051602061178583398151915291610337906114f6565b5f336103c68185856109ee565b834211156107ee5760405163313c898160e11b815260048101859052602401610706565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886108588c6001600160a01b03165f9081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6108b282610ca0565b90505f6108c182878787610ccc565b9050896001600160a01b0316816001600160a01b031614610908576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610706565b6109138a8a8a610984565b50505050505050505050565b610928826103f3565b61093181610a4b565b61042f8383610b02565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6104768383836001610cf8565b5f61099c848461093b565b90505f19811461042f57818110156109e057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610706565b61042f84848484035f610cf8565b6001600160a01b038316610a1757604051634b637e8f60e11b81525f6004820152602401610706565b6001600160a01b038216610a405760405163ec442f0560e01b81525f6004820152602401610706565b610476838383610ddc565b610a558133610f15565b50565b5f5f805160206117c5833981519152610a718484610749565b610af0575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610aa63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061030e565b5f91505061030e565b5f61043e610f4e565b5f5f805160206117c5833981519152610b1b8484610749565b15610af0575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061030e565b610b83610fc1565b610b8d828261100c565b5050565b610b99610fc1565b5f805160206117a58339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102610bd284826116a2565b5060038101610be183826116a2565b505f8082556001909101555050565b6001600160a01b038216610c195760405163ec442f0560e01b81525f6004820152602401610706565b610b8d5f8383610ddc565b5f807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00610672565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060915f805160206117a583398151915291610337906114f6565b60605f5f805160206117a5833981519152610326565b5f61030e610cac610af9565b8360405161190160f01b8152600281019290925260228201526042902090565b5f805f80610cdc8888888861105c565b925092509250610cec8282611124565b50909695505050505050565b5f805160206117858339815191526001600160a01b038516610d2f5760405163e602df0560e01b81525f6004820152602401610706565b6001600160a01b038416610d5857604051634a1406b160e11b81525f6004820152602401610706565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610dd557836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610dcc91815260200190565b60405180910390a35b5050505050565b5f805160206117858339815191526001600160a01b038416610e165781816002015f828254610e0b919061175d565b90915550610e869050565b6001600160a01b0384165f9081526020829052604090205482811015610e685760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610706565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316610ea4576002810180548390039055610ec2565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f0791815260200190565b60405180910390a350505050565b610f1f8282610749565b610b8d5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610706565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610f786111dc565b610f80611244565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661100a57604051631afcd79f60e31b815260040160405180910390fd5b565b611014610fc1565b5f805160206117858339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361104d84826116a2565b506004810161042f83826116a2565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109557505f9150600390508261111a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110e6573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661111157505f92506001915082905061111a565b92505f91508190505b9450945094915050565b5f82600381111561113757611137611770565b03611140575050565b600182600381111561115457611154611770565b036111725760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561118657611186611770565b036111a75760405163fce698f760e01b815260048101829052602401610706565b60038260038111156111bb576111bb611770565b03610b8d576040516335e2f38360e21b815260048101829052602401610706565b5f5f805160206117a5833981519152816111f4610c4c565b80519091501561120c57805160209091012092915050565b8154801561121b579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f5f805160206117a58339815191528161125c610c8a565b80519091501561127457805160209091012092915050565b6001820154801561121b579392505050565b5f60208284031215611296575f80fd5b81356001600160e01b0319811681146112ad575f80fd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6112ad60208301846112b4565b80356001600160a01b038116811461130a575f80fd5b919050565b5f8060408385031215611320575f80fd5b611329836112f4565b946020939093013593505050565b5f805f60608486031215611349575f80fd5b611352846112f4565b9250611360602085016112f4565b929592945050506040919091013590565b5f60208284031215611381575f80fd5b5035919050565b5f8060408385031215611399575f80fd5b823591506113a9602084016112f4565b90509250929050565b5f80604083850312156113c3575f80fd5b6113cc836112f4565b91506113a9602084016112f4565b5f602082840312156113ea575f80fd5b6112ad826112f4565b60ff60f81b8816815260e060208201525f61141160e08301896112b4565b828103604084015261142381896112b4565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b8181101561147857835183526020938401939092019160010161145a565b50909b9a5050505050505050505050565b5f805f805f805f60e0888a03121561149f575f80fd5b6114a8886112f4565b96506114b6602089016112f4565b95506040880135945060608801359350608088013560ff811681146114d9575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b600181811c9082168061150a57607f821691505b60208210810361152857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b6001815b600184111561157d578085048111156115615761156161152e565b600184161561156f57908102905b60019390931c928002611546565b935093915050565b5f826115935750600161030e565b8161159f57505f61030e565b81600181146115b557600281146115bf576115db565b600191505061030e565b60ff8411156115d0576115d061152e565b50506001821b61030e565b5060208310610133831016604e8410600b84101617156115fe575081810a61030e565b61160a5f198484611542565b805f190482111561161d5761161d61152e565b029392505050565b5f6112ad60ff841683611585565b808202811582820484141761030e5761030e61152e565b634e487b7160e01b5f52604160045260245ffd5b601f82111561047657805f5260205f20601f840160051c810160208510156116835750805b601f840160051c820191505b81811015610dd5575f815560010161168f565b815167ffffffffffffffff8111156116bc576116bc61164a565b6116d0816116ca84546114f6565b8461165e565b6020601f821160018114611702575f83156116eb5750848201515b5f19600385901b1c1916600184901b178455610dd5565b5f84815260208120601f198516915b828110156117315787850151825560209485019460019092019101611711565b508482101561174e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8082018082111561030e5761030e61152e565b634e487b7160e01b5f52602160045260245ffdfe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a26469706673582212200c213e57e697f2dee37f51b79647b3593da8c247917d58e21e2647bf25597abc64736f6c634300081a0033","sourceMap":"299:1259:112:-:0;;;447:39;;;;;;;;;-1:-1:-1;462:22:112;:20;:22::i;:::-;299:1259;;7711:422:25;8870:21;7900:15;;;;;;;7896:76;;;7938:23;;-1:-1:-1;;;7938:23:25;;;;;;;;;;;7896:76;7985:14;;-1:-1:-1;;;;;7985:14:25;;;:34;7981:146;;8035:33;;-1:-1:-1;;;;;;8035:33:25;-1:-1:-1;;;;;8035:33:25;;;;;8087:29;;158:50:137;;;8087:29:25;;146:2:137;131:18;8087:29:25;;;;;;;7981:146;7760:373;7711:422::o;14:200:137:-;299:1259:112;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561000f575f80fd5b5060043610610132575f3560e01c8063485cc955116100b457806395d89b411161007957806395d89b4114610283578063a217fddf1461028b578063a9059cbb14610292578063d505accf146102a5578063d547741f146102b8578063dd62ed3e146102cb575f80fd5b8063485cc9551461021c57806370a082311461022f5780637ecebe001461024257806384b0196e1461025557806391d1485414610270575f80fd5b8063248a9ca3116100fa578063248a9ca3146101ca5780632f2ff15d146101dd578063313ce567146101f25780633644e5151461020157806336568abe14610209575f80fd5b806301ffc9a71461013657806306fdde031461015e578063095ea7b31461017357806318160ddd1461018657806323b872dd146101b7575b5f80fd5b610149610144366004611286565b6102de565b60405190151581526020015b60405180910390f35b610166610314565b60405161015591906112e2565b61014961018136600461130f565b6103b9565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610155565b6101496101c5366004611337565b6103d0565b6101a96101d8366004611371565b6103f3565b6101f06101eb366004611388565b610413565b005b60405160088152602001610155565b6101a9610435565b6101f0610217366004611388565b610443565b6101f061022a3660046113b2565b61047b565b6101a961023d3660046113da565b610661565b6101a96102503660046113da565b610691565b61025d61069b565b60405161015597969594939291906113f3565b61014961027e366004611388565b610749565b61016661077f565b6101a95f81565b6101496102a036600461130f565b6107bd565b6101f06102b3366004611489565b6107ca565b6101f06102c6366004611388565b61091f565b6101a96102d93660046113b2565b61093b565b5f6001600160e01b03198216637965db0b60e01b148061030e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60605f5f805160206117858339815191525b9050806003018054610337906114f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610363906114f6565b80156103ae5780601f10610385576101008083540402835291602001916103ae565b820191905f5260205f20905b81548152906001019060200180831161039157829003601f168201915b505050505091505090565b5f336103c6818585610984565b5060019392505050565b5f336103dd858285610991565b6103e88585856109ee565b506001949350505050565b5f9081525f805160206117c5833981519152602052604090206001015490565b61041c826103f3565b61042581610a4b565b61042f8383610a58565b50505050565b5f61043e610af9565b905090565b6001600160a01b038116331461046c5760405163334bd91960e11b815260040160405180910390fd5b6104768282610b02565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156104c05750825b90505f8267ffffffffffffffff1660011480156104dc5750303b155b9050811580156104ea575080155b156105085760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561053257845460ff60401b1916600160401b1785555b6001600160a01b0387161580159061055257506001600160a01b03861615155b61055a575f80fd5b6105a060405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060048152602001634d4f564560e01b815250610b7b565b6105e360405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060018152602001603160f81b815250610b91565b6105ed5f88610a58565b50610612866105fe6008600a611625565b61060d906402540be400611633565b610bf0565b831561065857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f805f805160206117858339815191525b6001600160a01b039093165f9081526020939093525050604090205490565b5f61030e82610c24565b5f60608082808083815f805160206117a583398151915280549091501580156106c657506001810154155b61070f5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b610717610c4c565b61071f610c8a565b604080515f80825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b5f9182525f805160206117c5833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f8051602061178583398151915291610337906114f6565b5f336103c68185856109ee565b834211156107ee5760405163313c898160e11b815260048101859052602401610706565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886108588c6001600160a01b03165f9081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6108b282610ca0565b90505f6108c182878787610ccc565b9050896001600160a01b0316816001600160a01b031614610908576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610706565b6109138a8a8a610984565b50505050505050505050565b610928826103f3565b61093181610a4b565b61042f8383610b02565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6104768383836001610cf8565b5f61099c848461093b565b90505f19811461042f57818110156109e057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610706565b61042f84848484035f610cf8565b6001600160a01b038316610a1757604051634b637e8f60e11b81525f6004820152602401610706565b6001600160a01b038216610a405760405163ec442f0560e01b81525f6004820152602401610706565b610476838383610ddc565b610a558133610f15565b50565b5f5f805160206117c5833981519152610a718484610749565b610af0575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610aa63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061030e565b5f91505061030e565b5f61043e610f4e565b5f5f805160206117c5833981519152610b1b8484610749565b15610af0575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061030e565b610b83610fc1565b610b8d828261100c565b5050565b610b99610fc1565b5f805160206117a58339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102610bd284826116a2565b5060038101610be183826116a2565b505f8082556001909101555050565b6001600160a01b038216610c195760405163ec442f0560e01b81525f6004820152602401610706565b610b8d5f8383610ddc565b5f807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00610672565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060915f805160206117a583398151915291610337906114f6565b60605f5f805160206117a5833981519152610326565b5f61030e610cac610af9565b8360405161190160f01b8152600281019290925260228201526042902090565b5f805f80610cdc8888888861105c565b925092509250610cec8282611124565b50909695505050505050565b5f805160206117858339815191526001600160a01b038516610d2f5760405163e602df0560e01b81525f6004820152602401610706565b6001600160a01b038416610d5857604051634a1406b160e11b81525f6004820152602401610706565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610dd557836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610dcc91815260200190565b60405180910390a35b5050505050565b5f805160206117858339815191526001600160a01b038416610e165781816002015f828254610e0b919061175d565b90915550610e869050565b6001600160a01b0384165f9081526020829052604090205482811015610e685760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610706565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316610ea4576002810180548390039055610ec2565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f0791815260200190565b60405180910390a350505050565b610f1f8282610749565b610b8d5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610706565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610f786111dc565b610f80611244565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661100a57604051631afcd79f60e31b815260040160405180910390fd5b565b611014610fc1565b5f805160206117858339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361104d84826116a2565b506004810161042f83826116a2565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109557505f9150600390508261111a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110e6573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661111157505f92506001915082905061111a565b92505f91508190505b9450945094915050565b5f82600381111561113757611137611770565b03611140575050565b600182600381111561115457611154611770565b036111725760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561118657611186611770565b036111a75760405163fce698f760e01b815260048101829052602401610706565b60038260038111156111bb576111bb611770565b03610b8d576040516335e2f38360e21b815260048101829052602401610706565b5f5f805160206117a5833981519152816111f4610c4c565b80519091501561120c57805160209091012092915050565b8154801561121b579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f5f805160206117a58339815191528161125c610c8a565b80519091501561127457805160209091012092915050565b6001820154801561121b579392505050565b5f60208284031215611296575f80fd5b81356001600160e01b0319811681146112ad575f80fd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6112ad60208301846112b4565b80356001600160a01b038116811461130a575f80fd5b919050565b5f8060408385031215611320575f80fd5b611329836112f4565b946020939093013593505050565b5f805f60608486031215611349575f80fd5b611352846112f4565b9250611360602085016112f4565b929592945050506040919091013590565b5f60208284031215611381575f80fd5b5035919050565b5f8060408385031215611399575f80fd5b823591506113a9602084016112f4565b90509250929050565b5f80604083850312156113c3575f80fd5b6113cc836112f4565b91506113a9602084016112f4565b5f602082840312156113ea575f80fd5b6112ad826112f4565b60ff60f81b8816815260e060208201525f61141160e08301896112b4565b828103604084015261142381896112b4565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b8181101561147857835183526020938401939092019160010161145a565b50909b9a5050505050505050505050565b5f805f805f805f60e0888a03121561149f575f80fd5b6114a8886112f4565b96506114b6602089016112f4565b95506040880135945060608801359350608088013560ff811681146114d9575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b600181811c9082168061150a57607f821691505b60208210810361152857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b6001815b600184111561157d578085048111156115615761156161152e565b600184161561156f57908102905b60019390931c928002611546565b935093915050565b5f826115935750600161030e565b8161159f57505f61030e565b81600181146115b557600281146115bf576115db565b600191505061030e565b60ff8411156115d0576115d061152e565b50506001821b61030e565b5060208310610133831016604e8410600b84101617156115fe575081810a61030e565b61160a5f198484611542565b805f190482111561161d5761161d61152e565b029392505050565b5f6112ad60ff841683611585565b808202811582820484141761030e5761030e61152e565b634e487b7160e01b5f52604160045260245ffd5b601f82111561047657805f5260205f20601f840160051c810160208510156116835750805b601f840160051c820191505b81811015610dd5575f815560010161168f565b815167ffffffffffffffff8111156116bc576116bc61164a565b6116d0816116ca84546114f6565b8461165e565b6020601f821160018114611702575f83156116eb5750848201515b5f19600385901b1c1916600184901b178455610dd5565b5f84815260208120601f198516915b828110156117315787850151825560209485019460019092019101611711565b508482101561174e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8082018082111561030e5761030e61152e565b634e487b7160e01b5f52602160045260245ffdfe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a26469706673582212200c213e57e697f2dee37f51b79647b3593da8c247917d58e21e2647bf25597abc64736f6c634300081a0033","sourceMap":"299:1259:112:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3443:202:24;;;;;;:::i;:::-;;:::i;:::-;;;470:14:137;;463:22;445:41;;433:2;418:18;3443:202:24;;;;;;;;3011:144:27;;;:::i;:::-;;;;;;;:::i;5505:186::-;;;;;;:::i;:::-;;:::i;4191:152::-;4322:14;;4191:152;;;1645:25:137;;;1633:2;1618:18;4191:152:27;1499:177:137;6251:244:27;;;;;;:::i;:::-;;:::i;4759:191:24:-;;;;;;:::i;:::-;;:::i;5246:136::-;;;;;;:::i;:::-;;:::i;:::-;;1474:82:112;;;1548:1;2920:36:137;;2908:2;2893:18;1474:82:112;2778:184:137;3082:112:28;;;:::i;6348:245:24:-;;;;;;:::i;:::-;;:::i;981:342:112:-;;;;;;:::i;:::-;;:::i;4401:171:27:-;;;;;;:::i;:::-;;:::i;2821:154:28:-;;;;;;:::i;:::-;;:::i;5173:903:31:-;;;:::i;:::-;;;;;;;;;;;;;:::i;3732:207:24:-;;;;;;:::i;:::-;;:::i;3268:148:27:-;;;:::i;2317:49:24:-;;2362:4;2317:49;;4767:178:27;;;;;;:::i;:::-;;:::i;2095:672:28:-;;;;;;:::i;:::-;;:::i;5662:138:24:-;;;;;;:::i;:::-;;:::i;5003:195:27:-;;;;;;:::i;:::-;;:::i;3443:202:24:-;3528:4;-1:-1:-1;;;;;;3551:47:24;;-1:-1:-1;;;3551:47:24;;:87;;-1:-1:-1;;;;;;;;;;1133:40:32;;;3602:36:24;3544:94;3443:202;-1:-1:-1;;3443:202:24:o;3011:144:27:-;3056:13;3081:22;-1:-1:-1;;;;;;;;;;;3106:18:27;3081:43;;3141:1;:7;;3134:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3011:144;:::o;5505:186::-;5578:4;966:10:29;5632:31:27;966:10:29;5648:7:27;5657:5;5632:8;:31::i;:::-;-1:-1:-1;5680:4:27;;5505:186;-1:-1:-1;;;5505:186:27:o;6251:244::-;6338:4;966:10:29;6394:37:27;6410:4;966:10:29;6425:5:27;6394:15;:37::i;:::-;6441:26;6451:4;6457:2;6461:5;6441:9;:26::i;:::-;-1:-1:-1;6484:4:27;;6251:244;-1:-1:-1;;;;6251:244:27:o;4759:191:24:-;4824:7;4919:14;;;-1:-1:-1;;;;;;;;;;;4919:14:24;;;;;:24;;;;4759:191::o;5246:136::-;5320:18;5333:4;5320:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5350:25:::1;5361:4;5367:7;5350:10;:25::i;:::-;;5246:136:::0;;;:::o;3082:112:28:-;3141:7;3167:20;:18;:20::i;:::-;3160:27;;3082:112;:::o;6348:245:24:-;-1:-1:-1;;;;;6441:34:24;;966:10:29;6441:34:24;6437:102;;6498:30;;-1:-1:-1;;;6498:30:24;;;;;;;;;;;6437:102;6549:37;6561:4;6567:18;6549:11;:37::i;:::-;;6348:245;;:::o;981:342:112:-;8870:21:25;4302:15;;-1:-1:-1;;;4302:15:25;;;;4301:16;;4348:14;;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;:16;;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:25;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:25;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:25;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:25;-1:-1:-1;;;5013:22:25;;;4979:67;-1:-1:-1;;;;;1072:20:112;::::1;::::0;;::::1;::::0;:46:::1;;-1:-1:-1::0;;;;;;1096:22:112;::::1;::::0;::::1;1072:46;1064:55;;;::::0;::::1;;1129:32;;;;;;;;;;;;;;-1:-1:-1::0;;;1129:32:112::1;;::::0;::::1;;;;;;;;;;;;;-1:-1:-1::0;;;1129:32:112::1;;::::0;:12:::1;:32::i;:::-;1171:40;;;;;;;;;;;;;;-1:-1:-1::0;;;1171:40:112::1;;::::0;::::1;;;;;;;;;;;;;-1:-1:-1::0;;;1171:40:112::1;;::::0;:23:::1;:40::i;:::-;1221:38;2362:4:24;1252:6:112::0;1221:10:::1;:38::i;:::-;-1:-1:-1::0;1269:47:112::1;1275:8:::0;1299:16:::1;1548:1:::0;1299:2:::1;:16;:::i;:::-;1285:30;::::0;:11:::1;:30;:::i;:::-;1269:5;:47::i;:::-;5070:14:25::0;5066:101;;;5100:23;;-1:-1:-1;;;;5100:23:25;;;5142:14;;-1:-1:-1;7849:50:137;;5142:14:25;;7837:2:137;7822:18;5142:14:25;;;;;;;5066:101;4092:1081;;;;;981:342:112;;:::o;4401:171:27:-;4466:7;;-1:-1:-1;;;;;;;;;;;4510:18:27;-1:-1:-1;;;;;4545:20:27;;;:11;:20;;;;;;;;-1:-1:-1;;4545:20:27;;;;;4401:171::o;2821:154:28:-;2923:7;2949:19;2962:5;2949:12;:19::i;5173:903:31:-;5271:13;5298:18;;5271:13;;;5298:18;5271:13;-1:-1:-1;;;;;;;;;;;5777:13:31;;5511:45;;-1:-1:-1;5777:18:31;:43;;;;-1:-1:-1;5799:16:31;;;;:21;5777:43;5769:77;;;;-1:-1:-1;;;5769:77:31;;8112:2:137;5769:77:31;;;8094:21:137;8151:2;8131:18;;;8124:30;-1:-1:-1;;;8170:18:137;;;8163:51;8231:18;;5769:77:31;;;;;;;;;5908:13;:11;:13::i;:::-;5935:16;:14;:16::i;:::-;6043;;;6027:1;6043:16;;;;;;;;;-1:-1:-1;;;5857:212:31;;;-1:-1:-1;5857:212:31;;-1:-1:-1;5965:13:31;;-1:-1:-1;6000:4:31;;-1:-1:-1;6027:1:31;-1:-1:-1;6043:16:31;-1:-1:-1;5857:212:31;-1:-1:-1;;5173:903:31:o;3732:207:24:-;3809:4;3901:14;;;-1:-1:-1;;;;;;;;;;;3901:14:24;;;;;;;;-1:-1:-1;;;;;3901:31:24;;;;;;;;;;;;;;;3732:207::o;3268:148:27:-;3400:9;3393:16;;3315:13;;-1:-1:-1;;;;;;;;;;;2359:20:27;3393:16;;;:::i;4767:178::-;4836:4;966:10:29;4890:27:27;966:10:29;4907:2:27;4911:5;4890:9;:27::i;2095:672:28:-;2316:8;2298:15;:26;2294:97;;;2347:33;;-1:-1:-1;;;2347:33:28;;;;;1645:25:137;;;1618:18;;2347:33:28;1499:177:137;2294:97:28;2401:18;1277:95;2460:5;2467:7;2476:5;2483:16;2493:5;-1:-1:-1;;;;;1954:16:30;1597:7;1954:16;;;1005:21;1954:16;;;;;:18;;;;;;;;;1537:452;2483:16:28;2432:78;;;;;;8679:25:137;;;;-1:-1:-1;;;;;8740:32:137;;;8720:18;;;8713:60;8809:32;;;;8789:18;;;8782:60;8858:18;;;8851:34;8901:19;;;8894:35;8945:19;;;8938:35;;;8651:19;;2432:78:28;;;;;;;;;;;;2422:89;;;;;;2401:110;;2522:12;2537:28;2554:10;2537:16;:28::i;:::-;2522:43;;2576:14;2593:28;2607:4;2613:1;2616;2619;2593:13;:28::i;:::-;2576:45;;2645:5;-1:-1:-1;;;;;2635:15:28;:6;-1:-1:-1;;;;;2635:15:28;;2631:88;;2673:35;;-1:-1:-1;;;2673:35:28;;-1:-1:-1;;;;;9176:32:137;;;2673:35:28;;;9158:51:137;9245:32;;9225:18;;;9218:60;9131:18;;2673:35:28;8984:300:137;2631:88:28;2729:31;2738:5;2745:7;2754:5;2729:8;:31::i;:::-;2284:483;;;2095:672;;;;;;;:::o;5662:138:24:-;5737:18;5750:4;5737:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5767:26:::1;5779:4;5785:7;5767:11;:26::i;5003:195:27:-:0;-1:-1:-1;;;;;5162:20:27;;;5083:7;5162:20;;;:13;:20;;;;;;;;:29;;;;;;;;;;;;;5003:195::o;10264:128::-;10348:37;10357:5;10364:7;10373:5;10380:4;10348:8;:37::i;11993:477::-;12092:24;12119:25;12129:5;12136:7;12119:9;:25::i;:::-;12092:52;;-1:-1:-1;;12158:16:27;:37;12154:310;;12234:5;12215:16;:24;12211:130;;;12266:60;;-1:-1:-1;;;12266:60:27;;-1:-1:-1;;;;;9509:32:137;;12266:60:27;;;9491:51:137;9558:18;;;9551:34;;;9601:18;;;9594:34;;;9464:18;;12266:60:27;9289:345:137;12211:130:27;12382:57;12391:5;12398:7;12426:5;12407:16;:24;12433:5;12382:8;:57::i;6868:300::-;-1:-1:-1;;;;;6951:18:27;;6947:86;;6992:30;;-1:-1:-1;;;6992:30:27;;7019:1;6992:30;;;9785:51:137;9758:18;;6992:30:27;9639:203:137;6947:86:27;-1:-1:-1;;;;;7046:16:27;;7042:86;;7085:32;;-1:-1:-1;;;7085:32:27;;7114:1;7085:32;;;9785:51:137;9758:18;;7085:32:27;9639:203:137;7042:86:27;7137:24;7145:4;7151:2;7155:5;7137:7;:24::i;4148:103:24:-;4214:30;4225:4;966:10:29;4214::24;:30::i;:::-;4148:103;:::o;7270:387::-;7347:4;-1:-1:-1;;;;;;;;;;;7437:22:24;7445:4;7451:7;7437;:22::i;:::-;7432:219;;7475:8;:14;;;;;;;;;;;-1:-1:-1;;;;;7475:31:24;;;;;;;;;:38;;-1:-1:-1;;7475:38:24;7509:4;7475:38;;;7559:12;966:10:29;;887:96;7559:12:24;-1:-1:-1;;;;;7532:40:24;7550:7;-1:-1:-1;;;;;7532:40:24;7544:4;7532:40;;;;;;;;;;7593:4;7586:11;;;;;7432:219;7635:5;7628:12;;;;;4015:109:31;4068:7;4094:23;:21;:23::i;7892:388:24:-;7970:4;-1:-1:-1;;;;;;;;;;;8059:22:24;8067:4;8073:7;8059;:22::i;:::-;8055:219;;;8131:5;8097:14;;;;;;;;;;;-1:-1:-1;;;;;8097:31:24;;;;;;;;;;:39;;-1:-1:-1;;8097:39:24;;;8155:40;966:10:29;;8097:14:24;;8155:40;;8131:5;8155:40;8216:4;8209:11;;;;;2577:147:27;6931:20:25;:18;:20::i;:::-;2679:38:27::1;2702:5;2709:7;2679:22;:38::i;:::-;2577:147:::0;;:::o;3599:330:31:-;6931:20:25;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;3766:7:31;:14:::1;3776:4:::0;3766:7;:14:::1;:::i;:::-;-1:-1:-1::0;3790:10:31::1;::::0;::::1;:20;3803:7:::0;3790:10;:20:::1;:::i;:::-;-1:-1:-1::0;3891:1:31::1;3875:17:::0;;;3902:16:::1;::::0;;::::1;:20:::0;-1:-1:-1;;3599:330:31:o;8996:208:27:-;-1:-1:-1;;;;;9066:21:27;;9062:91;;9110:32;;-1:-1:-1;;;9110:32:27;;9139:1;9110:32;;;9785:51:137;9758:18;;9110:32:27;9639:203:137;9062:91:27;9162:35;9178:1;9182:7;9191:5;9162:7;:35::i;1259:164:30:-;1319:7;;1005:21;1364:19;886:156;6300:155:31;6441:7;6434:14;;6354:13;;-1:-1:-1;;;;;;;;;;;2839:21:31;6434:14;;;:::i;6682:161::-;6739:13;6764:23;-1:-1:-1;;;;;;;;;;;6790:19:31;2720:156;4946:176;5023:7;5049:66;5082:20;:18;:20::i;:::-;5104:10;3555:4:61;3549:11;-1:-1:-1;;;3573:23:61;;3625:4;3616:14;;3609:39;;;;3677:4;3668:14;;3661:34;3733:4;3718:20;;;3353:401;6803:260:60;6888:7;6908:17;6927:18;6947:16;6967:25;6978:4;6984:1;6987;6990;6967:10;:25::i;:::-;6907:85;;;;;;7002:28;7014:5;7021:8;7002:11;:28::i;:::-;-1:-1:-1;7047:9:60;;6803:260;-1:-1:-1;;;;;;6803:260:60:o;11224:487:27:-;-1:-1:-1;;;;;;;;;;;;;;;;11389:19:27;;11385:89;;11431:32;;-1:-1:-1;;;11431:32:27;;11460:1;11431:32;;;9785:51:137;9758:18;;11431:32:27;9639:203:137;11385:89:27;-1:-1:-1;;;;;11487:21:27;;11483:90;;11531:31;;-1:-1:-1;;;11531:31:27;;11559:1;11531:31;;;9785:51:137;9758:18;;11531:31:27;9639:203:137;11483:90:27;-1:-1:-1;;;;;11582:20:27;;;;;;;:13;;;:20;;;;;;;;:29;;;;;;;;;:37;;;11629:76;;;;11679:7;-1:-1:-1;;;;;11663:31:27;11672:5;-1:-1:-1;;;;;11663:31:27;;11688:5;11663:31;;;;1645:25:137;;1633:2;1618:18;;1499:177;11663:31:27;;;;;;;;11629:76;11322:389;11224:487;;;;:::o;7483:1170::-;-1:-1:-1;;;;;;;;;;;;;;;;7625:18:27;;7621:546;;7779:5;7761:1;:14;;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;7621:546:27;;-1:-1:-1;7621:546:27;;-1:-1:-1;;;;;7837:17:27;;7815:19;7837:17;;;;;;;;;;;7872:19;;;7868:115;;;7918:50;;-1:-1:-1;;;7918:50:27;;-1:-1:-1;;;;;9509:32:137;;7918:50:27;;;9491:51:137;9558:18;;;9551:34;;;9601:18;;;9594:34;;;9464:18;;7918:50:27;9289:345:137;7868:115:27;-1:-1:-1;;;;;8103:17:27;;:11;:17;;;;;;;;;;8123:19;;;;8103:39;;7621:546;-1:-1:-1;;;;;8181:16:27;;8177:429;;8344:14;;;:23;;;;;;;8177:429;;;-1:-1:-1;;;;;8557:15:27;;:11;:15;;;;;;;;;;:24;;;;;;8177:429;8636:2;-1:-1:-1;;;;;8621:25:27;8630:4;-1:-1:-1;;;;;8621:25:27;;8640:5;8621:25;;;;1645::137;;1633:2;1618:18;;1499:177;8621:25:27;;;;;;;;7558:1095;7483:1170;;;:::o;4381:197:24:-;4469:22;4477:4;4483:7;4469;:22::i;:::-;4464:108;;4514:47;;-1:-1:-1;;;4514:47:24;;-1:-1:-1;;;;;12293:32:137;;4514:47:24;;;12275:51:137;12342:18;;;12335:34;;;12248:18;;4514:47:24;12101:274:137;4130:191:31;4185:7;2073:95;4243:17;:15;:17::i;:::-;4262:20;:18;:20::i;:::-;4221:92;;;;;;12639:25:137;;;;12680:18;;12673:34;;;;12723:18;;;12716:34;4284:13:31;12766:18:137;;;12759:34;4307:4:31;12809:19:137;;;12802:61;12611:19;;4221:92:31;;;;;;;;;;;;4211:103;;;;;;4204:110;;4130:191;:::o;7084:141:25:-;8870:21;8560:40;-1:-1:-1;;;8560:40:25;;;;7146:73;;7191:17;;-1:-1:-1;;;7191:17:25;;;;;;;;;;;7146:73;7084:141::o;2730:216:27:-;6931:20:25;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;2895:7:27;:15:::1;2905:5:::0;2895:7;:15:::1;:::i;:::-;-1:-1:-1::0;2920:9:27::1;::::0;::::1;:19;2932:7:::0;2920:9;:19:::1;:::i;5140:1530:60:-:0;5266:7;;;6199:66;6186:79;;6182:164;;;-1:-1:-1;6297:1:60;;-1:-1:-1;6301:30:60;;-1:-1:-1;6333:1:60;6281:54;;6182:164;6457:24;;;6440:14;6457:24;;;;;;;;;13101:25:137;;;13174:4;13162:17;;13142:18;;;13135:45;;;;13196:18;;;13189:34;;;13239:18;;;13232:34;;;6457:24:60;;13073:19:137;;6457:24:60;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6457:24:60;;-1:-1:-1;;6457:24:60;;;-1:-1:-1;;;;;;;6495:20:60;;6491:113;;-1:-1:-1;6547:1:60;;-1:-1:-1;6551:29:60;;-1:-1:-1;6547:1:60;;-1:-1:-1;6531:62:60;;6491:113;6622:6;-1:-1:-1;6630:20:60;;-1:-1:-1;6630:20:60;;-1:-1:-1;5140:1530:60;;;;;;;;;:::o;7196:532::-;7291:20;7282:5;:29;;;;;;;;:::i;:::-;;7278:444;;7196:532;;:::o;7278:444::-;7387:29;7378:5;:38;;;;;;;;:::i;:::-;;7374:348;;7439:23;;-1:-1:-1;;;7439:23:60;;;;;;;;;;;7374:348;7492:35;7483:5;:44;;;;;;;;:::i;:::-;;7479:243;;7550:46;;-1:-1:-1;;;7550:46:60;;;;;1645:25:137;;;1618:18;;7550:46:60;1499:177:137;7479:243:60;7626:30;7617:5;:39;;;;;;;;:::i;:::-;;7613:109;;7679:32;;-1:-1:-1;;;7679:32:60;;;;;1645:25:137;;;1618:18;;7679:32:60;1499:177:137;7058:687:31;7108:7;-1:-1:-1;;;;;;;;;;;7108:7:31;7203:13;:11;:13::i;:::-;7230:18;;7182:34;;-1:-1:-1;7230:22:31;7226:513;;7275:22;;;;;;;;7058:687;-1:-1:-1;;7058:687:31:o;7226:513::-;7572:13;;7603:15;;7599:130;;7645:10;7058:687;-1:-1:-1;;;7058:687:31:o;7599:130::-;7701:13;7694:20;;;;;7058:687;:::o;7966:723::-;8019:7;-1:-1:-1;;;;;;;;;;;8019:7:31;8117:16;:14;:16::i;:::-;8147:21;;8093:40;;-1:-1:-1;8147:25:31;8143:540;;8195:25;;;;;;;;7966:723;-1:-1:-1;;7966:723:31:o;8143:540::-;8507:16;;;;8541:18;;8537:136;;8586:13;7966:723;-1:-1:-1;;;7966:723:31:o;14:286:137:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:137;;209:43;;199:71;;266:1;263;256:12;199:71;289:5;14:286;-1:-1:-1;;;14:286:137:o;497:289::-;539:3;577:5;571:12;604:6;599:3;592:19;660:6;653:4;646:5;642:16;635:4;630:3;626:14;620:47;712:1;705:4;696:6;691:3;687:16;683:27;676:38;775:4;768:2;764:7;759:2;751:6;747:15;743:29;738:3;734:39;730:50;723:57;;;497:289;;;;:::o;791:220::-;940:2;929:9;922:21;903:4;960:45;1001:2;990:9;986:18;978:6;960:45;:::i;1016:173::-;1084:20;;-1:-1:-1;;;;;1133:31:137;;1123:42;;1113:70;;1179:1;1176;1169:12;1113:70;1016:173;;;:::o;1194:300::-;1262:6;1270;1323:2;1311:9;1302:7;1298:23;1294:32;1291:52;;;1339:1;1336;1329:12;1291:52;1362:29;1381:9;1362:29;:::i;:::-;1352:39;1460:2;1445:18;;;;1432:32;;-1:-1:-1;;;1194:300:137:o;1681:374::-;1758:6;1766;1774;1827:2;1815:9;1806:7;1802:23;1798:32;1795:52;;;1843:1;1840;1833:12;1795:52;1866:29;1885:9;1866:29;:::i;:::-;1856:39;;1914:38;1948:2;1937:9;1933:18;1914:38;:::i;:::-;1681:374;;1904:48;;-1:-1:-1;;;2021:2:137;2006:18;;;;1993:32;;1681:374::o;2060:226::-;2119:6;2172:2;2160:9;2151:7;2147:23;2143:32;2140:52;;;2188:1;2185;2178:12;2140:52;-1:-1:-1;2233:23:137;;2060:226;-1:-1:-1;2060:226:137:o;2473:300::-;2541:6;2549;2602:2;2590:9;2581:7;2577:23;2573:32;2570:52;;;2618:1;2615;2608:12;2570:52;2663:23;;;-1:-1:-1;2729:38:137;2763:2;2748:18;;2729:38;:::i;:::-;2719:48;;2473:300;;;;;:::o;2967:260::-;3035:6;3043;3096:2;3084:9;3075:7;3071:23;3067:32;3064:52;;;3112:1;3109;3102:12;3064:52;3135:29;3154:9;3135:29;:::i;:::-;3125:39;;3183:38;3217:2;3206:9;3202:18;3183:38;:::i;3232:186::-;3291:6;3344:2;3332:9;3323:7;3319:23;3315:32;3312:52;;;3360:1;3357;3350:12;3312:52;3383:29;3402:9;3383:29;:::i;3423:1238::-;3829:3;3824;3820:13;3812:6;3808:26;3797:9;3790:45;3871:3;3866:2;3855:9;3851:18;3844:31;3771:4;3898:46;3939:3;3928:9;3924:19;3916:6;3898:46;:::i;:::-;3992:9;3984:6;3980:22;3975:2;3964:9;3960:18;3953:50;4026:33;4052:6;4044;4026:33;:::i;:::-;4090:2;4075:18;;4068:34;;;-1:-1:-1;;;;;4139:32:137;;4133:3;4118:19;;4111:61;4159:3;4188:19;;4181:35;;;4253:22;;;4247:3;4232:19;;4225:51;4325:13;;4347:22;;;4397:2;4423:15;;;;-1:-1:-1;4385:15:137;;;;-1:-1:-1;4466:169:137;4480:6;4477:1;4474:13;4466:169;;;4541:13;;4529:26;;4584:2;4610:15;;;;4575:12;;;;4502:1;4495:9;4466:169;;;-1:-1:-1;4652:3:137;;3423:1238;-1:-1:-1;;;;;;;;;;;3423:1238:137:o;4666:903::-;4777:6;4785;4793;4801;4809;4817;4825;4878:3;4866:9;4857:7;4853:23;4849:33;4846:53;;;4895:1;4892;4885:12;4846:53;4918:29;4937:9;4918:29;:::i;:::-;4908:39;;4966:38;5000:2;4989:9;4985:18;4966:38;:::i;:::-;4956:48;-1:-1:-1;5073:2:137;5058:18;;5045:32;;-1:-1:-1;5174:2:137;5159:18;;5146:32;;-1:-1:-1;5256:3:137;5241:19;;5228:33;5305:4;5292:18;;5280:31;;5270:59;;5325:1;5322;5315:12;5270:59;4666:903;;;;-1:-1:-1;4666:903:137;;;;5348:7;5428:3;5413:19;;5400:33;;-1:-1:-1;5532:3:137;5517:19;;;5504:33;;4666:903;-1:-1:-1;;4666:903:137:o;5574:380::-;5653:1;5649:12;;;;5696;;;5717:61;;5771:4;5763:6;5759:17;5749:27;;5717:61;5824:2;5816:6;5813:14;5793:18;5790:38;5787:161;;5870:10;5865:3;5861:20;5858:1;5851:31;5905:4;5902:1;5895:15;5933:4;5930:1;5923:15;5787:161;;5574:380;;;:::o;5959:127::-;6020:10;6015:3;6011:20;6008:1;6001:31;6051:4;6048:1;6041:15;6075:4;6072:1;6065:15;6091:375;6179:1;6197:5;6211:249;6232:1;6222:8;6219:15;6211:249;;;6282:4;6277:3;6273:14;6267:4;6264:24;6261:50;;;6291:18;;:::i;:::-;6341:1;6331:8;6327:16;6324:49;;;6355:16;;;;6324:49;6438:1;6434:16;;;;;6394:15;;6211:249;;;6091:375;;;;;;:::o;6471:902::-;6520:5;6550:8;6540:80;;-1:-1:-1;6591:1:137;6605:5;;6540:80;6639:4;6629:76;;-1:-1:-1;6676:1:137;6690:5;;6629:76;6721:4;6739:1;6734:59;;;;6807:1;6802:174;;;;6714:262;;6734:59;6764:1;6755:10;;6778:5;;;6802:174;6839:3;6829:8;6826:17;6823:43;;;6846:18;;:::i;:::-;-1:-1:-1;;6902:1:137;6888:16;;6961:5;;6714:262;;7060:2;7050:8;7047:16;7041:3;7035:4;7032:13;7028:36;7022:2;7012:8;7009:16;7004:2;6998:4;6995:12;6991:35;6988:77;6985:203;;;-1:-1:-1;7097:19:137;;;7173:5;;6985:203;7220:42;-1:-1:-1;;7245:8:137;7239:4;7220:42;:::i;:::-;7298:6;7294:1;7290:6;7286:19;7277:7;7274:32;7271:58;;;7309:18;;:::i;:::-;7347:20;;6471:902;-1:-1:-1;;;6471:902:137:o;7378:140::-;7436:5;7465:47;7506:4;7496:8;7492:19;7486:4;7465:47;:::i;7523:168::-;7596:9;;;7627;;7644:15;;;7638:22;;7624:37;7614:71;;7665:18;;:::i;8260:127::-;8321:10;8316:3;8312:20;8309:1;8302:31;8352:4;8349:1;8342:15;8376:4;8373:1;8366:15;9973:518;10075:2;10070:3;10067:11;10064:421;;;10111:5;10108:1;10101:16;10155:4;10152:1;10142:18;10225:2;10213:10;10209:19;10206:1;10202:27;10196:4;10192:38;10261:4;10249:10;10246:20;10243:47;;;-1:-1:-1;10284:4:137;10243:47;10339:2;10334:3;10330:12;10327:1;10323:20;10317:4;10313:31;10303:41;;10394:81;10412:2;10405:5;10402:13;10394:81;;;10471:1;10457:16;;10438:1;10427:13;10394:81;;10667:1299;10793:3;10787:10;10820:18;10812:6;10809:30;10806:56;;;10842:18;;:::i;:::-;10871:97;10961:6;10921:38;10953:4;10947:11;10921:38;:::i;:::-;10915:4;10871:97;:::i;:::-;11017:4;11048:2;11037:14;;11065:1;11060:649;;;;11753:1;11770:6;11767:89;;;-1:-1:-1;11822:19:137;;;11816:26;11767:89;-1:-1:-1;;10624:1:137;10620:11;;;10616:24;10612:29;10602:40;10648:1;10644:11;;;10599:57;11869:81;;11030:930;;11060:649;9920:1;9913:14;;;9957:4;9944:18;;-1:-1:-1;;11096:20:137;;;11214:222;11228:7;11225:1;11222:14;11214:222;;;11310:19;;;11304:26;11289:42;;11417:4;11402:20;;;;11370:1;11358:14;;;;11244:12;11214:222;;;11218:3;11464:6;11455:7;11452:19;11449:201;;;11525:19;;;11519:26;-1:-1:-1;;11608:1:137;11604:14;;;11620:3;11600:24;11596:37;11592:42;11577:58;11562:74;;11449:201;-1:-1:-1;;;;11696:1:137;11680:14;;;11676:22;11663:36;;-1:-1:-1;10667:1299:137:o;11971:125::-;12036:9;;;12057:10;;;12054:36;;;12070:18;;:::i;13277:127::-;13338:10;13333:3;13329:20;13326:1;13319:31;13369:4;13366:1;13359:15;13393:4;13390:1;13383:15","linkReferences":{}},"methodIdentifiers":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DOMAIN_SEPARATOR()":"3644e515","allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","decimals()":"313ce567","eip712Domain()":"84b0196e","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","initialize(address,address)":"485cc955","name()":"06fdde03","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7","symbol()":"95d89b41","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"name\":\"ERC2612ExpiredSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC2612InvalidSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentNonce\",\"type\":\"uint256\"}],\"name\":\"InvalidAccountNonce\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"EIP712DomainChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip712Domain\",\"outputs\":[{\"internalType\":\"bytes1\",\"name\":\"fields\",\"type\":\"bytes1\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"verifyingContract\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"salt\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"extensions\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_custody\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"ECDSAInvalidSignature()\":[{\"details\":\"The signature derives the `address(0)`.\"}],\"ECDSAInvalidSignatureLength(uint256)\":[{\"details\":\"The signature has an invalid length.\"}],\"ECDSAInvalidSignatureS(bytes32)\":[{\"details\":\"The signature has an S value that is in the upper half order.\"}],\"ERC20InsufficientAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failure with the `spender`\\u2019s `allowance`. Used in transfers.\",\"params\":{\"allowance\":\"Amount of tokens a `spender` is allowed to operate with.\",\"needed\":\"Minimum amount required to perform a transfer.\",\"spender\":\"Address that may be allowed to operate on tokens without being their owner.\"}}],\"ERC20InsufficientBalance(address,uint256,uint256)\":[{\"details\":\"Indicates an error related to the current `balance` of a `sender`. Used in transfers.\",\"params\":{\"balance\":\"Current balance for the interacting account.\",\"needed\":\"Minimum amount required to perform a transfer.\",\"sender\":\"Address whose tokens are being transferred.\"}}],\"ERC20InvalidApprover(address)\":[{\"details\":\"Indicates a failure with the `approver` of a token to be approved. Used in approvals.\",\"params\":{\"approver\":\"Address initiating an approval operation.\"}}],\"ERC20InvalidReceiver(address)\":[{\"details\":\"Indicates a failure with the token `receiver`. Used in transfers.\",\"params\":{\"receiver\":\"Address to which tokens are being transferred.\"}}],\"ERC20InvalidSender(address)\":[{\"details\":\"Indicates a failure with the token `sender`. Used in transfers.\",\"params\":{\"sender\":\"Address whose tokens are being transferred.\"}}],\"ERC20InvalidSpender(address)\":[{\"details\":\"Indicates a failure with the `spender` to be approved. Used in approvals.\",\"params\":{\"spender\":\"Address that may be allowed to operate on tokens without being their owner.\"}}],\"ERC2612ExpiredSignature(uint256)\":[{\"details\":\"Permit deadline has expired.\"}],\"ERC2612InvalidSigner(address,address)\":[{\"details\":\"Mismatched signature.\"}],\"InvalidAccountNonce(address,uint256)\":[{\"details\":\"The nonce used for an `account` is not the expected current nonce.\"}],\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"EIP712DomainChanged()\":{\"details\":\"MAY be emitted to signal that the domain could have changed.\"},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. NOTE: If `value` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"constructor\":{\"details\":\"Disables potential implementation exploit\"},\"decimals()\":{\"details\":\"Returns the number of decimals\"},\"eip712Domain()\":{\"details\":\"See {IERC-5267}.\"},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"initialize(address,address)\":{\"details\":\"Initializes the contract with initial parameters.\",\"params\":{\"_custody\":\"The address of the custody account.\",\"_owner\":\"The address of the owner who receives default admin role.\"}},\"name()\":{\"details\":\"Returns the name of the token.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `value`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `value`. - the caller must have allowance for ``from``'s tokens of at least `value`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"decimals()\":{\"notice\":\"decimals is set to 8, following the Movement network standard decimals\"},\"initialize(address,address)\":{\"notice\":\"The ERC20 token is named \\\"Movement\\\" with symbol \\\"MOVE\\\".EIP712 domain version is set to \\\"1\\\" for signatures.The owner is granted the `DEFAULT_ADMIN_ROLE`.10 billion MOVE tokens are minted to the owner's address.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/token/MOVEToken.sol\":\"MOVEToken\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@createx/=lib/createx/src/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@safe-smart-account/=lib/safe-smart-account/\",\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":murky/=lib/murky/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/\",\":openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/\",\":safe-smart-account/=lib/safe-smart-account/\",\":solady/=lib/createx/lib/solady/\",\":solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\":{\"keccak256\":\"0x6662ec4e5cefca03eeadd073e9469df8d2944bb2ee8ec8f7622c2c46aab5f225\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4d8544c6f8daa4d1bc215c6a72fe0acdb748664a105b0e5efc19295667521d45\",\"dweb:/ipfs/QmdGWqdnXT8S3RgCR6aV8XHZrsybieMQLLnug1NtpSjEXN\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609\",\"dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol\":{\"keccak256\":\"0x9a1766b1921bf91b3e61eb53c7a6e70725254befd4bdcbbcd3af40bd9f66856f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29bf2fa41a172086a665c9738377b93655aa4b1ffda9fe839c8bdf646f185040\",\"dweb:/ipfs/QmeB21qDuo8WPQSrqXJbQmWHKsdeocGNSUWLhCwniVejrt\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol\":{\"keccak256\":\"0x8a97653aeba40e9f0c2e8df1a1379b29b927b6dc3534040c668e71ad9ae89d88\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e529c294c9d634eb68a1e4aeb66eb8381de5a08ccd2c0bfeebd48a6b28fcff7\",\"dweb:/ipfs/QmWCezuxfZb68nM3Hs6XzQNNiW7VJsymU4sajy2DW1CKbp\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9\",\"dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol\":{\"keccak256\":\"0x778f4a1546a1c6c726ecc8e2348a2789690fb8f26e12bd9d89537669167b79a4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://851d3dfe724e918ff0a064b206e1ef46b27ab0df2aa2c8af976973a22ef59827\",\"dweb:/ipfs/Qmd4wb7zX8ueYhMVBy5PJjfsANK3Ra3pKPN7qQkNsdwGHn\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol\":{\"keccak256\":\"0x85462422a22578744581e012e9aa0a391958cb360288b0b63f29bf0431d70327\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2bc529e2b9b28da5d26da451058250d85afcaa3c5083ee273ac68fa6bf956b78\",\"dweb:/ipfs/Qmd3Aq59ztmoVmHigsaR4YjkXWKERVpjfQ4a2PHk7Ke6Rx\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol\":{\"keccak256\":\"0xdaba3f7c42c55b2896353f32bd27d4d5f8bae741b3b05d4c53f67abc4dc47ce8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1fa2e61141c602510bcd2cd936ed9561922ac8772a9b9c9a9db091a74e354a45\",\"dweb:/ipfs/QmcHQDDoEBwJmwUbzoVkytvJsBx3KVHYFFnDkvRGWh9Wmh\"]},\"lib/openzeppelin-contracts/contracts/access/IAccessControl.sol\":{\"keccak256\":\"0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1fd2f35495652e57e3f99bc6c510bc5f7dd398a176ea2e72d8ed730aebc6ca26\",\"dweb:/ipfs/QmTQV6X4gkikTib49cho5iDX3JvSQbdsoEChoDwrk3CbbH\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol\":{\"keccak256\":\"0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a\",\"dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP\"]},\"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol\":{\"keccak256\":\"0x60c65f701957fdd6faea1acb0bb45825791d473693ed9ecb34726fdfaa849dd7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ea290300e0efc4d901244949dc4d877fd46e6c5e43dc2b26620e8efab3ab803f\",\"dweb:/ipfs/QmcLLJppxKeJWqHxE2CUkcfhuRTgHSn8J4kijcLa5MYhSt\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ea104e577e63faea3b69c415637e99e755dcbf64c5833d7140c35a714d6d90c\",\"dweb:/ipfs/Qmau6x4Ns9XdyynRCNNp3RhLqijJjFm7z5fyZazfYFGYdq\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0xaa761817f6cd7892fcf158b3c776b34551cde36f48ff9703d53898bc45a94ea2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ad7c8d4d08938c8dfc43d75a148863fb324b80cf53e0a36f7e5a4ac29008850\",\"dweb:/ipfs/QmcrhfPgVNf5mkdhQvy1pMv51TFokD3Y4Wa5WZhFqVh8UV\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"keccak256\":\"0x6008dabfe393240d73d7dd7688033f72740d570aa422254d29a7dce8568f3aff\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f5196ec75139918c6c7bb4251b36395e668f1fa6d206beba7e7520e74913940d\",\"dweb:/ipfs/QmSyqjksXxmm2mCG6qRd1yuwLykypkSVBbnBnGqJRcuJMi\"]},\"lib/openzeppelin-contracts/contracts/utils/Strings.sol\":{\"keccak256\":\"0x55f102ea785d8399c0e58d1108e2d289506dde18abc6db1b7f68c1f9f9bc5792\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e52e0a7765c943ef14e5bcf11e46e6139fa044be564881378349236bf2e3453\",\"dweb:/ipfs/QmZEeeXoFPW47amyP35gfzomF9DixqqTEPwzBakv6cZw6i\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0xeed0a08b0b091f528356cbc7245891a4c748682d4f6a18055e8e6ca77d12a6cf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba80ba06c8e6be852847e4c5f4492cef801feb6558ae09ed705ff2e04ea8b13c\",\"dweb:/ipfs/QmXRJDv3xHLVQCVXg1ZvR35QS9sij5y9NDWYzMfUfAdTHF\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol\":{\"keccak256\":\"0xba333517a3add42cd35fe877656fc3dfcc9de53baa4f3aabbd6d12a92e4ea435\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2ceacff44c0fdc81e48e0e0b1db87a2076d3c1fb497341de077bf1da9f6b406c\",\"dweb:/ipfs/QmRUo1muMRAewxrKQ7TkXUtknyRoR57AyEkoPpiuZQ8FzX\"]},\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://87b3541437c8c443ccd36795e56a338ed12855eec17f8da624511b8d1a7e14df\",\"dweb:/ipfs/QmeJQCtZrQjtJLr6u7ZHWeH3pBnjtLWzvRrKViAi7UZqxL\"]},\"lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0x005ec64c6313f0555d59e278f9a7a5ab2db5bdc72a027f255a37c327af1ec02d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4ece9f0b9c8daca08c76b6b5405a6446b6f73b3a15fab7ff56e296cbd4a2c875\",\"dweb:/ipfs/QmQyRpyPRL5SQuAgj6SHmbir3foX65FJjbVTTQrA2EFg6L\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0x5f7e4076e175393767754387c962926577f1660dd9b810187b9002407656be72\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7d533a1c97cd43a57cd9c465f7ee8dd0e39ae93a8fb8ff8e5303a356b081cdcc\",\"dweb:/ipfs/QmVBEei6aTnvYNZp2CHYVNKyZS4q1KkjANfY39WVXZXVoT\"]},\"src/token/MOVEToken.sol\":{\"keccak256\":\"0x907babd7e2db7867a9401ab8edcecd579ad7db099ae4693a27e052887d91eb22\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a87e3b44d5e5409f0695ca2057be132b02b12a6cfa3d95a1a69382458e16b20a\",\"dweb:/ipfs/QmPNA8kiRGr3jR4ngz8UeKLUM7QitN4J5xNbxxWYNncV9H\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.26+commit.8a97fa7a"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"AccessControlBadConfirmation"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"type":"error","name":"AccessControlUnauthorizedAccount"},{"inputs":[],"type":"error","name":"ECDSAInvalidSignature"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"type":"error","name":"ECDSAInvalidSignatureLength"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"type":"error","name":"ECDSAInvalidSignatureS"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"type":"error","name":"ERC20InsufficientAllowance"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"type":"error","name":"ERC20InsufficientBalance"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"type":"error","name":"ERC20InvalidApprover"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"type":"error","name":"ERC20InvalidReceiver"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"type":"error","name":"ERC20InvalidSender"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"type":"error","name":"ERC20InvalidSpender"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"type":"error","name":"ERC2612ExpiredSignature"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"type":"error","name":"ERC2612InvalidSigner"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"type":"error","name":"InvalidAccountNonce"},{"inputs":[],"type":"error","name":"InvalidInitialization"},{"inputs":[],"type":"error","name":"NotInitializing"},{"inputs":[{"internalType":"address","name":"owner","type":"address","indexed":true},{"internalType":"address","name":"spender","type":"address","indexed":true},{"internalType":"uint256","name":"value","type":"uint256","indexed":false}],"type":"event","name":"Approval","anonymous":false},{"inputs":[],"type":"event","name":"EIP712DomainChanged","anonymous":false},{"inputs":[{"internalType":"uint64","name":"version","type":"uint64","indexed":false}],"type":"event","name":"Initialized","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"previousAdminRole","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"newAdminRole","type":"bytes32","indexed":true}],"type":"event","name":"RoleAdminChanged","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleGranted","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleRevoked","anonymous":false},{"inputs":[{"internalType":"address","name":"from","type":"address","indexed":true},{"internalType":"address","name":"to","type":"address","indexed":true},{"internalType":"uint256","name":"value","type":"uint256","indexed":false}],"type":"event","name":"Transfer","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"stateMutability":"view","type":"function","name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"pure","type":"function","name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"stateMutability":"view","type":"function","name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"grantRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_custody","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"initialize"},{"inputs":[],"stateMutability":"view","type":"function","name":"name","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function","name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"stateMutability":"nonpayable","type":"function","name":"permit"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"renounceRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"revokeRole"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"allowance(address,address)":{"details":"See {IERC20-allowance}."},"approve(address,uint256)":{"details":"See {IERC20-approve}. NOTE: If `value` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address."},"balanceOf(address)":{"details":"See {IERC20-balanceOf}."},"constructor":{"details":"Disables potential implementation exploit"},"decimals()":{"details":"Returns the number of decimals"},"eip712Domain()":{"details":"See {IERC-5267}."},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"initialize(address,address)":{"details":"Initializes the contract with initial parameters.","params":{"_custody":"The address of the custody account.","_owner":"The address of the owner who receives default admin role."}},"name()":{"details":"Returns the name of the token."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."},"symbol()":{"details":"Returns the symbol of the token, usually a shorter version of the name."},"totalSupply()":{"details":"See {IERC20-totalSupply}."},"transfer(address,uint256)":{"details":"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `value`."},"transferFrom(address,address,uint256)":{"details":"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `value`. - the caller must have allowance for ``from``'s tokens of at least `value`."}},"version":1},"userdoc":{"kind":"user","methods":{"decimals()":{"notice":"decimals is set to 8, following the Movement network standard decimals"},"initialize(address,address)":{"notice":"The ERC20 token is named \"Movement\" with symbol \"MOVE\".EIP712 domain version is set to \"1\" for signatures.The owner is granted the `DEFAULT_ADMIN_ROLE`.10 billion MOVE tokens are minted to the owner's address."}},"version":1}},"settings":{"remappings":["@createx/=lib/createx/src/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@safe-smart-account/=lib/safe-smart-account/","ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","murky/=lib/murky/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/","openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/","safe-smart-account/=lib/safe-smart-account/","solady/=lib/createx/lib/solady/","solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/","solmate/=lib/solmate/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/token/MOVEToken.sol":"MOVEToken"},"evmVersion":"cancun","libraries":{}},"sources":{"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol":{"keccak256":"0x6662ec4e5cefca03eeadd073e9469df8d2944bb2ee8ec8f7622c2c46aab5f225","urls":["bzz-raw://4d8544c6f8daa4d1bc215c6a72fe0acdb748664a105b0e5efc19295667521d45","dweb:/ipfs/QmdGWqdnXT8S3RgCR6aV8XHZrsybieMQLLnug1NtpSjEXN"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"keccak256":"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b","urls":["bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609","dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol":{"keccak256":"0x9a1766b1921bf91b3e61eb53c7a6e70725254befd4bdcbbcd3af40bd9f66856f","urls":["bzz-raw://29bf2fa41a172086a665c9738377b93655aa4b1ffda9fe839c8bdf646f185040","dweb:/ipfs/QmeB21qDuo8WPQSrqXJbQmWHKsdeocGNSUWLhCwniVejrt"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol":{"keccak256":"0x8a97653aeba40e9f0c2e8df1a1379b29b927b6dc3534040c668e71ad9ae89d88","urls":["bzz-raw://6e529c294c9d634eb68a1e4aeb66eb8381de5a08ccd2c0bfeebd48a6b28fcff7","dweb:/ipfs/QmWCezuxfZb68nM3Hs6XzQNNiW7VJsymU4sajy2DW1CKbp"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"keccak256":"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397","urls":["bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9","dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol":{"keccak256":"0x778f4a1546a1c6c726ecc8e2348a2789690fb8f26e12bd9d89537669167b79a4","urls":["bzz-raw://851d3dfe724e918ff0a064b206e1ef46b27ab0df2aa2c8af976973a22ef59827","dweb:/ipfs/Qmd4wb7zX8ueYhMVBy5PJjfsANK3Ra3pKPN7qQkNsdwGHn"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol":{"keccak256":"0x85462422a22578744581e012e9aa0a391958cb360288b0b63f29bf0431d70327","urls":["bzz-raw://2bc529e2b9b28da5d26da451058250d85afcaa3c5083ee273ac68fa6bf956b78","dweb:/ipfs/Qmd3Aq59ztmoVmHigsaR4YjkXWKERVpjfQ4a2PHk7Ke6Rx"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol":{"keccak256":"0xdaba3f7c42c55b2896353f32bd27d4d5f8bae741b3b05d4c53f67abc4dc47ce8","urls":["bzz-raw://1fa2e61141c602510bcd2cd936ed9561922ac8772a9b9c9a9db091a74e354a45","dweb:/ipfs/QmcHQDDoEBwJmwUbzoVkytvJsBx3KVHYFFnDkvRGWh9Wmh"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"keccak256":"0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41","urls":["bzz-raw://1fd2f35495652e57e3f99bc6c510bc5f7dd398a176ea2e72d8ed730aebc6ca26","dweb:/ipfs/QmTQV6X4gkikTib49cho5iDX3JvSQbdsoEChoDwrk3CbbH"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol":{"keccak256":"0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92","urls":["bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a","dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol":{"keccak256":"0x60c65f701957fdd6faea1acb0bb45825791d473693ed9ecb34726fdfaa849dd7","urls":["bzz-raw://ea290300e0efc4d901244949dc4d877fd46e6c5e43dc2b26620e8efab3ab803f","dweb:/ipfs/QmcLLJppxKeJWqHxE2CUkcfhuRTgHSn8J4kijcLa5MYhSt"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"keccak256":"0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70","urls":["bzz-raw://0ea104e577e63faea3b69c415637e99e755dcbf64c5833d7140c35a714d6d90c","dweb:/ipfs/Qmau6x4Ns9XdyynRCNNp3RhLqijJjFm7z5fyZazfYFGYdq"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"keccak256":"0xaa761817f6cd7892fcf158b3c776b34551cde36f48ff9703d53898bc45a94ea2","urls":["bzz-raw://0ad7c8d4d08938c8dfc43d75a148863fb324b80cf53e0a36f7e5a4ac29008850","dweb:/ipfs/QmcrhfPgVNf5mkdhQvy1pMv51TFokD3Y4Wa5WZhFqVh8UV"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol":{"keccak256":"0x6008dabfe393240d73d7dd7688033f72740d570aa422254d29a7dce8568f3aff","urls":["bzz-raw://f5196ec75139918c6c7bb4251b36395e668f1fa6d206beba7e7520e74913940d","dweb:/ipfs/QmSyqjksXxmm2mCG6qRd1yuwLykypkSVBbnBnGqJRcuJMi"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/Strings.sol":{"keccak256":"0x55f102ea785d8399c0e58d1108e2d289506dde18abc6db1b7f68c1f9f9bc5792","urls":["bzz-raw://6e52e0a7765c943ef14e5bcf11e46e6139fa044be564881378349236bf2e3453","dweb:/ipfs/QmZEeeXoFPW47amyP35gfzomF9DixqqTEPwzBakv6cZw6i"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"keccak256":"0xeed0a08b0b091f528356cbc7245891a4c748682d4f6a18055e8e6ca77d12a6cf","urls":["bzz-raw://ba80ba06c8e6be852847e4c5f4492cef801feb6558ae09ed705ff2e04ea8b13c","dweb:/ipfs/QmXRJDv3xHLVQCVXg1ZvR35QS9sij5y9NDWYzMfUfAdTHF"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol":{"keccak256":"0xba333517a3add42cd35fe877656fc3dfcc9de53baa4f3aabbd6d12a92e4ea435","urls":["bzz-raw://2ceacff44c0fdc81e48e0e0b1db87a2076d3c1fb497341de077bf1da9f6b406c","dweb:/ipfs/QmRUo1muMRAewxrKQ7TkXUtknyRoR57AyEkoPpiuZQ8FzX"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b","urls":["bzz-raw://87b3541437c8c443ccd36795e56a338ed12855eec17f8da624511b8d1a7e14df","dweb:/ipfs/QmeJQCtZrQjtJLr6u7ZHWeH3pBnjtLWzvRrKViAi7UZqxL"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"keccak256":"0x005ec64c6313f0555d59e278f9a7a5ab2db5bdc72a027f255a37c327af1ec02d","urls":["bzz-raw://4ece9f0b9c8daca08c76b6b5405a6446b6f73b3a15fab7ff56e296cbd4a2c875","dweb:/ipfs/QmQyRpyPRL5SQuAgj6SHmbir3foX65FJjbVTTQrA2EFg6L"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol":{"keccak256":"0x5f7e4076e175393767754387c962926577f1660dd9b810187b9002407656be72","urls":["bzz-raw://7d533a1c97cd43a57cd9c465f7ee8dd0e39ae93a8fb8ff8e5303a356b081cdcc","dweb:/ipfs/QmVBEei6aTnvYNZp2CHYVNKyZS4q1KkjANfY39WVXZXVoT"],"license":"MIT"},"src/token/MOVEToken.sol":{"keccak256":"0x907babd7e2db7867a9401ab8edcecd579ad7db099ae4693a27e052887d91eb22","urls":["bzz-raw://a87e3b44d5e5409f0695ca2057be132b02b12a6cfa3d95a1a69382458e16b20a","dweb:/ipfs/QmPNA8kiRGr3jR4ngz8UeKLUM7QitN4J5xNbxxWYNncV9H"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"ast":{"absolutePath":"src/token/MOVEToken.sol","id":56720,"exportedSymbols":{"AccessControlUpgradeable":[39385],"ERC20PermitUpgradeable":[40607],"MOVEToken":[56719]},"nodeType":"SourceUnit","src":"32:1526:112","nodes":[{"id":56640,"nodeType":"PragmaDirective","src":"32:24:112","nodes":[],"literals":["solidity","^","0.8",".19"]},{"id":56642,"nodeType":"ImportDirective","src":"58:125:112","nodes":[],"absolutePath":"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol","file":"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol","nameLocation":"-1:-1:-1","scope":56720,"sourceUnit":40608,"symbolAliases":[{"foreign":{"id":56641,"name":"ERC20PermitUpgradeable","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":40607,"src":"66:22:112","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":56644,"nodeType":"ImportDirective","src":"184:113:112","nodes":[],"absolutePath":"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol","file":"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol","nameLocation":"-1:-1:-1","scope":56720,"sourceUnit":39386,"symbolAliases":[{"foreign":{"id":56643,"name":"AccessControlUpgradeable","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39385,"src":"192:24:112","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":56719,"nodeType":"ContractDefinition","src":"299:1259:112","nodes":[{"id":56656,"nodeType":"FunctionDefinition","src":"447:39:112","nodes":[],"body":{"id":56655,"nodeType":"Block","src":"461:25:112","nodes":[],"statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":56652,"name":"_disableInitializers","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39607,"src":"462:20:112","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":56653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"462:22:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":56654,"nodeType":"ExpressionStatement","src":"462:22:112"}]},"documentation":{"id":56649,"nodeType":"StructuredDocumentation","src":"377:65:112","text":" @dev Disables potential implementation exploit"},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":56650,"nodeType":"ParameterList","parameters":[],"src":"458:2:112"},"returnParameters":{"id":56651,"nodeType":"ParameterList","parameters":[],"src":"461:0:112"},"scope":56719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":56708,"nodeType":"FunctionDefinition","src":"981:342:112","nodes":[],"body":{"id":56707,"nodeType":"Block","src":"1054:269:112","nodes":[],"statements":[{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_bool","typeString":"bool"},"id":56679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":56672,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":56667,"name":"_owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":56659,"src":"1072:6:112","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"hexValue":"30","id":56670,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1090:1:112","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"}],"id":56669,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1082:7:112","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":56668,"name":"address","nodeType":"ElementaryTypeName","src":"1082:7:112","typeDescriptions":{}}},"id":56671,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1082:10:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1072:20:112","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"BinaryOperation","operator":"&&","rightExpression":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":56678,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":56673,"name":"_custody","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":56661,"src":"1096:8:112","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"hexValue":"30","id":56676,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1116:1:112","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"}],"id":56675,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1108:7:112","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":56674,"name":"address","nodeType":"ElementaryTypeName","src":"1108:7:112","typeDescriptions":{}}},"id":56677,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1108:10:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1096:22:112","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"src":"1072:46:112","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":56666,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18,-18],"referencedDeclaration":-18,"src":"1064:7:112","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":56680,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1064:55:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":56681,"nodeType":"ExpressionStatement","src":"1064:55:112"},{"expression":{"arguments":[{"hexValue":"4d6f76656d656e74","id":56683,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1142:10:112","typeDescriptions":{"typeIdentifier":"t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252","typeString":"literal_string \"Movement\""},"value":"Movement"},{"hexValue":"4d4f5645","id":56684,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1154:6:112","typeDescriptions":{"typeIdentifier":"t_stringliteral_94304e8d07ec49123c30284d16c4a1082e90258cc0faf510314d9c3808edcda0","typeString":"literal_string \"MOVE\""},"value":"MOVE"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252","typeString":"literal_string \"Movement\""},{"typeIdentifier":"t_stringliteral_94304e8d07ec49123c30284d16c4a1082e90258cc0faf510314d9c3808edcda0","typeString":"literal_string \"MOVE\""}],"id":56682,"name":"__ERC20_init","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39889,"src":"1129:12:112","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":56685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1129:32:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":56686,"nodeType":"ExpressionStatement","src":"1129:32:112"},{"expression":{"arguments":[{"hexValue":"4d6f76656d656e74","id":56688,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1195:10:112","typeDescriptions":{"typeIdentifier":"t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252","typeString":"literal_string \"Movement\""},"value":"Movement"},{"hexValue":"31","id":56689,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1207:3:112","typeDescriptions":{"typeIdentifier":"t_stringliteral_c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6","typeString":"literal_string \"1\""},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252","typeString":"literal_string \"Movement\""},{"typeIdentifier":"t_stringliteral_c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6","typeString":"literal_string \"1\""}],"id":56687,"name":"__EIP712_init_unchained","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":40861,"src":"1171:23:112","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":56690,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1171:40:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":56691,"nodeType":"ExpressionStatement","src":"1171:40:112"},{"expression":{"arguments":[{"id":56693,"name":"DEFAULT_ADMIN_ROLE","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39051,"src":"1232:18:112","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":56694,"name":"_owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":56659,"src":"1252:6:112","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_address","typeString":"address"}],"id":56692,"name":"_grantRole","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39338,"src":"1221:10:112","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$_t_bool_$","typeString":"function (bytes32,address) returns (bool)"}},"id":56695,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1221:38:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":56696,"nodeType":"ExpressionStatement","src":"1221:38:112"},{"expression":{"arguments":[{"id":56698,"name":"_custody","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":56661,"src":"1275:8:112","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":56704,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"hexValue":"3130303030303030303030","id":56699,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1285:11:112","typeDescriptions":{"typeIdentifier":"t_rational_10000000000_by_1","typeString":"int_const 10000000000"},"value":"10000000000"},"nodeType":"BinaryOperation","operator":"*","rightExpression":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":56703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"hexValue":"3130","id":56700,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1299:2:112","typeDescriptions":{"typeIdentifier":"t_rational_10_by_1","typeString":"int_const 10"},"value":"10"},"nodeType":"BinaryOperation","operator":"**","rightExpression":{"arguments":[],"expression":{"argumentTypes":[],"id":56701,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[56718],"referencedDeclaration":56718,"src":"1305:8:112","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$__$returns$_t_uint8_$","typeString":"function () pure returns (uint8)"}},"id":56702,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1305:10:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"src":"1299:16:112","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"1285:30:112","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":56697,"name":"_mint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":40270,"src":"1269:5:112","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$__$","typeString":"function (address,uint256)"}},"id":56705,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1269:47:112","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":56706,"nodeType":"ExpressionStatement","src":"1269:47:112"}]},"documentation":{"id":56657,"nodeType":"StructuredDocumentation","src":"492:484:112","text":" @dev Initializes the contract with initial parameters.\n @param _owner The address of the owner who receives default admin role.\n @param _custody The address of the custody account.\n @notice The ERC20 token is named \"Movement\" with symbol \"MOVE\".\n @notice EIP712 domain version is set to \"1\" for signatures.\n @notice The owner is granted the `DEFAULT_ADMIN_ROLE`.\n @notice 10 billion MOVE tokens are minted to the owner's address."},"functionSelector":"485cc955","implemented":true,"kind":"function","modifiers":[{"id":56664,"kind":"modifierInvocation","modifierName":{"id":56663,"name":"initializer","nameLocations":["1042:11:112"],"nodeType":"IdentifierPath","referencedDeclaration":39493,"src":"1042:11:112"},"nodeType":"ModifierInvocation","src":"1042:11:112"}],"name":"initialize","nameLocation":"990:10:112","parameters":{"id":56662,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56659,"mutability":"mutable","name":"_owner","nameLocation":"1009:6:112","nodeType":"VariableDeclaration","scope":56708,"src":"1001:14:112","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56658,"name":"address","nodeType":"ElementaryTypeName","src":"1001:7:112","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":56661,"mutability":"mutable","name":"_custody","nameLocation":"1025:8:112","nodeType":"VariableDeclaration","scope":56708,"src":"1017:16:112","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56660,"name":"address","nodeType":"ElementaryTypeName","src":"1017:7:112","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1000:34:112"},"returnParameters":{"id":56665,"nodeType":"ParameterList","parameters":[],"src":"1054:0:112"},"scope":56719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":56718,"nodeType":"FunctionDefinition","src":"1474:82:112","nodes":[],"body":{"id":56717,"nodeType":"Block","src":"1531:25:112","nodes":[],"statements":[{"expression":{"hexValue":"38","id":56715,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1548:1:112","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"functionReturnParameters":56714,"id":56716,"nodeType":"Return","src":"1541:8:112"}]},"baseFunctions":[39958],"documentation":{"id":56709,"nodeType":"StructuredDocumentation","src":"1329:140:112","text":" @dev Returns the number of decimals\n @notice decimals is set to 8, following the Movement network standard decimals"},"functionSelector":"313ce567","implemented":true,"kind":"function","modifiers":[],"name":"decimals","nameLocation":"1483:8:112","overrides":{"id":56711,"nodeType":"OverrideSpecifier","overrides":[],"src":"1506:8:112"},"parameters":{"id":56710,"nodeType":"ParameterList","parameters":[],"src":"1491:2:112"},"returnParameters":{"id":56714,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56713,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":56718,"src":"1524:5:112","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":56712,"name":"uint8","nodeType":"ElementaryTypeName","src":"1524:5:112","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"}],"src":"1523:7:112"},"scope":56719,"stateMutability":"pure","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[{"baseName":{"id":56645,"name":"ERC20PermitUpgradeable","nameLocations":["321:22:112"],"nodeType":"IdentifierPath","referencedDeclaration":40607,"src":"321:22:112"},"id":56646,"nodeType":"InheritanceSpecifier","src":"321:22:112"},{"baseName":{"id":56647,"name":"AccessControlUpgradeable","nameLocations":["345:24:112"],"nodeType":"IdentifierPath","referencedDeclaration":39385,"src":"345:24:112"},"id":56648,"nodeType":"InheritanceSpecifier","src":"345:24:112"}],"canonicalName":"MOVEToken","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[56719,39385,41148,45166,41527,40607,40764,41108,42745,43725,40438,42797,43689,43663,40653,39639],"name":"MOVEToken","nameLocation":"308:9:112","scope":56720,"usedErrors":[39402,39405,40473,40480,40667,41454,41457,42767,42772,42777,42786,42791,42796,44719,44724,44729],"usedEvents":[39410,41466,41475,41484,42725,43597,43606]}],"license":"MIT"},"id":112} \ No newline at end of file +{ + "abi": [ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "eip712Domain", + "inputs": [], + "outputs": [ + { + "name": "fields", + "type": "bytes1", + "internalType": "bytes1" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "version", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "verifyingContract", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "extensions", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "_owner", + "type": "address", + "internalType": "address" + }, + { + "name": "_custody", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EIP712DomainChanged", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ECDSAInvalidSignature", + "inputs": [] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureS", + "inputs": [ + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ERC20InsufficientAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "allowance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC20InsufficientBalance", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidApprover", + "inputs": [ + { + "name": "approver", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidReceiver", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSpender", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC2612ExpiredSignature", + "inputs": [ + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC2612InvalidSigner", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidAccountNonce", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "currentNonce", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b61181a806100d65f395ff3fe608060405234801561000f575f80fd5b5060043610610132575f3560e01c8063485cc955116100b457806395d89b411161007957806395d89b4114610283578063a217fddf1461028b578063a9059cbb14610292578063d505accf146102a5578063d547741f146102b8578063dd62ed3e146102cb575f80fd5b8063485cc9551461021c57806370a082311461022f5780637ecebe001461024257806384b0196e1461025557806391d1485414610270575f80fd5b8063248a9ca3116100fa578063248a9ca3146101ca5780632f2ff15d146101dd578063313ce567146101f25780633644e5151461020157806336568abe14610209575f80fd5b806301ffc9a71461013657806306fdde031461015e578063095ea7b31461017357806318160ddd1461018657806323b872dd146101b7575b5f80fd5b610149610144366004611286565b6102de565b60405190151581526020015b60405180910390f35b610166610314565b60405161015591906112e2565b61014961018136600461130f565b6103b9565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610155565b6101496101c5366004611337565b6103d0565b6101a96101d8366004611371565b6103f3565b6101f06101eb366004611388565b610413565b005b60405160088152602001610155565b6101a9610435565b6101f0610217366004611388565b610443565b6101f061022a3660046113b2565b61047b565b6101a961023d3660046113da565b610661565b6101a96102503660046113da565b610691565b61025d61069b565b60405161015597969594939291906113f3565b61014961027e366004611388565b610749565b61016661077f565b6101a95f81565b6101496102a036600461130f565b6107bd565b6101f06102b3366004611489565b6107ca565b6101f06102c6366004611388565b61091f565b6101a96102d93660046113b2565b61093b565b5f6001600160e01b03198216637965db0b60e01b148061030e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60605f5f805160206117858339815191525b9050806003018054610337906114f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610363906114f6565b80156103ae5780601f10610385576101008083540402835291602001916103ae565b820191905f5260205f20905b81548152906001019060200180831161039157829003601f168201915b505050505091505090565b5f336103c6818585610984565b5060019392505050565b5f336103dd858285610991565b6103e88585856109ee565b506001949350505050565b5f9081525f805160206117c5833981519152602052604090206001015490565b61041c826103f3565b61042581610a4b565b61042f8383610a58565b50505050565b5f61043e610af9565b905090565b6001600160a01b038116331461046c5760405163334bd91960e11b815260040160405180910390fd5b6104768282610b02565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156104c05750825b90505f8267ffffffffffffffff1660011480156104dc5750303b155b9050811580156104ea575080155b156105085760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561053257845460ff60401b1916600160401b1785555b6001600160a01b0387161580159061055257506001600160a01b03861615155b61055a575f80fd5b6105a060405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060048152602001634d4f564560e01b815250610b7b565b6105e360405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060018152602001603160f81b815250610b91565b6105ed5f88610a58565b50610612866105fe6008600a611625565b61060d906402540be400611633565b610bf0565b831561065857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f805f805160206117858339815191525b6001600160a01b039093165f9081526020939093525050604090205490565b5f61030e82610c24565b5f60608082808083815f805160206117a583398151915280549091501580156106c657506001810154155b61070f5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b610717610c4c565b61071f610c8a565b604080515f80825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b5f9182525f805160206117c5833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f8051602061178583398151915291610337906114f6565b5f336103c68185856109ee565b834211156107ee5760405163313c898160e11b815260048101859052602401610706565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886108588c6001600160a01b03165f9081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6108b282610ca0565b90505f6108c182878787610ccc565b9050896001600160a01b0316816001600160a01b031614610908576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610706565b6109138a8a8a610984565b50505050505050505050565b610928826103f3565b61093181610a4b565b61042f8383610b02565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6104768383836001610cf8565b5f61099c848461093b565b90505f19811461042f57818110156109e057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610706565b61042f84848484035f610cf8565b6001600160a01b038316610a1757604051634b637e8f60e11b81525f6004820152602401610706565b6001600160a01b038216610a405760405163ec442f0560e01b81525f6004820152602401610706565b610476838383610ddc565b610a558133610f15565b50565b5f5f805160206117c5833981519152610a718484610749565b610af0575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610aa63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061030e565b5f91505061030e565b5f61043e610f4e565b5f5f805160206117c5833981519152610b1b8484610749565b15610af0575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061030e565b610b83610fc1565b610b8d828261100c565b5050565b610b99610fc1565b5f805160206117a58339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102610bd284826116a2565b5060038101610be183826116a2565b505f8082556001909101555050565b6001600160a01b038216610c195760405163ec442f0560e01b81525f6004820152602401610706565b610b8d5f8383610ddc565b5f807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00610672565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060915f805160206117a583398151915291610337906114f6565b60605f5f805160206117a5833981519152610326565b5f61030e610cac610af9565b8360405161190160f01b8152600281019290925260228201526042902090565b5f805f80610cdc8888888861105c565b925092509250610cec8282611124565b50909695505050505050565b5f805160206117858339815191526001600160a01b038516610d2f5760405163e602df0560e01b81525f6004820152602401610706565b6001600160a01b038416610d5857604051634a1406b160e11b81525f6004820152602401610706565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610dd557836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610dcc91815260200190565b60405180910390a35b5050505050565b5f805160206117858339815191526001600160a01b038416610e165781816002015f828254610e0b919061175d565b90915550610e869050565b6001600160a01b0384165f9081526020829052604090205482811015610e685760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610706565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316610ea4576002810180548390039055610ec2565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f0791815260200190565b60405180910390a350505050565b610f1f8282610749565b610b8d5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610706565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610f786111dc565b610f80611244565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661100a57604051631afcd79f60e31b815260040160405180910390fd5b565b611014610fc1565b5f805160206117858339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361104d84826116a2565b506004810161042f83826116a2565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109557505f9150600390508261111a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110e6573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661111157505f92506001915082905061111a565b92505f91508190505b9450945094915050565b5f82600381111561113757611137611770565b03611140575050565b600182600381111561115457611154611770565b036111725760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561118657611186611770565b036111a75760405163fce698f760e01b815260048101829052602401610706565b60038260038111156111bb576111bb611770565b03610b8d576040516335e2f38360e21b815260048101829052602401610706565b5f5f805160206117a5833981519152816111f4610c4c565b80519091501561120c57805160209091012092915050565b8154801561121b579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f5f805160206117a58339815191528161125c610c8a565b80519091501561127457805160209091012092915050565b6001820154801561121b579392505050565b5f60208284031215611296575f80fd5b81356001600160e01b0319811681146112ad575f80fd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6112ad60208301846112b4565b80356001600160a01b038116811461130a575f80fd5b919050565b5f8060408385031215611320575f80fd5b611329836112f4565b946020939093013593505050565b5f805f60608486031215611349575f80fd5b611352846112f4565b9250611360602085016112f4565b929592945050506040919091013590565b5f60208284031215611381575f80fd5b5035919050565b5f8060408385031215611399575f80fd5b823591506113a9602084016112f4565b90509250929050565b5f80604083850312156113c3575f80fd5b6113cc836112f4565b91506113a9602084016112f4565b5f602082840312156113ea575f80fd5b6112ad826112f4565b60ff60f81b8816815260e060208201525f61141160e08301896112b4565b828103604084015261142381896112b4565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b8181101561147857835183526020938401939092019160010161145a565b50909b9a5050505050505050505050565b5f805f805f805f60e0888a03121561149f575f80fd5b6114a8886112f4565b96506114b6602089016112f4565b95506040880135945060608801359350608088013560ff811681146114d9575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b600181811c9082168061150a57607f821691505b60208210810361152857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b6001815b600184111561157d578085048111156115615761156161152e565b600184161561156f57908102905b60019390931c928002611546565b935093915050565b5f826115935750600161030e565b8161159f57505f61030e565b81600181146115b557600281146115bf576115db565b600191505061030e565b60ff8411156115d0576115d061152e565b50506001821b61030e565b5060208310610133831016604e8410600b84101617156115fe575081810a61030e565b61160a5f198484611542565b805f190482111561161d5761161d61152e565b029392505050565b5f6112ad60ff841683611585565b808202811582820484141761030e5761030e61152e565b634e487b7160e01b5f52604160045260245ffd5b601f82111561047657805f5260205f20601f840160051c810160208510156116835750805b601f840160051c820191505b81811015610dd5575f815560010161168f565b815167ffffffffffffffff8111156116bc576116bc61164a565b6116d0816116ca84546114f6565b8461165e565b6020601f821160018114611702575f83156116eb5750848201515b5f19600385901b1c1916600184901b178455610dd5565b5f84815260208120601f198516915b828110156117315787850151825560209485019460019092019101611711565b508482101561174e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8082018082111561030e5761030e61152e565b634e487b7160e01b5f52602160045260245ffdfe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a26469706673582212200c213e57e697f2dee37f51b79647b3593da8c247917d58e21e2647bf25597abc64736f6c634300081a0033", + "sourceMap": "299:1259:112:-:0;;;447:39;;;;;;;;;-1:-1:-1;462:22:112;:20;:22::i;:::-;299:1259;;7711:422:25;8870:21;7900:15;;;;;;;7896:76;;;7938:23;;-1:-1:-1;;;7938:23:25;;;;;;;;;;;7896:76;7985:14;;-1:-1:-1;;;;;7985:14:25;;;:34;7981:146;;8035:33;;-1:-1:-1;;;;;;8035:33:25;-1:-1:-1;;;;;8035:33:25;;;;;8087:29;;158:50:137;;;8087:29:25;;146:2:137;131:18;8087:29:25;;;;;;;7981:146;7760:373;7711:422::o;14:200:137:-;299:1259:112;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f80fd5b5060043610610132575f3560e01c8063485cc955116100b457806395d89b411161007957806395d89b4114610283578063a217fddf1461028b578063a9059cbb14610292578063d505accf146102a5578063d547741f146102b8578063dd62ed3e146102cb575f80fd5b8063485cc9551461021c57806370a082311461022f5780637ecebe001461024257806384b0196e1461025557806391d1485414610270575f80fd5b8063248a9ca3116100fa578063248a9ca3146101ca5780632f2ff15d146101dd578063313ce567146101f25780633644e5151461020157806336568abe14610209575f80fd5b806301ffc9a71461013657806306fdde031461015e578063095ea7b31461017357806318160ddd1461018657806323b872dd146101b7575b5f80fd5b610149610144366004611286565b6102de565b60405190151581526020015b60405180910390f35b610166610314565b60405161015591906112e2565b61014961018136600461130f565b6103b9565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610155565b6101496101c5366004611337565b6103d0565b6101a96101d8366004611371565b6103f3565b6101f06101eb366004611388565b610413565b005b60405160088152602001610155565b6101a9610435565b6101f0610217366004611388565b610443565b6101f061022a3660046113b2565b61047b565b6101a961023d3660046113da565b610661565b6101a96102503660046113da565b610691565b61025d61069b565b60405161015597969594939291906113f3565b61014961027e366004611388565b610749565b61016661077f565b6101a95f81565b6101496102a036600461130f565b6107bd565b6101f06102b3366004611489565b6107ca565b6101f06102c6366004611388565b61091f565b6101a96102d93660046113b2565b61093b565b5f6001600160e01b03198216637965db0b60e01b148061030e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60605f5f805160206117858339815191525b9050806003018054610337906114f6565b80601f0160208091040260200160405190810160405280929190818152602001828054610363906114f6565b80156103ae5780601f10610385576101008083540402835291602001916103ae565b820191905f5260205f20905b81548152906001019060200180831161039157829003601f168201915b505050505091505090565b5f336103c6818585610984565b5060019392505050565b5f336103dd858285610991565b6103e88585856109ee565b506001949350505050565b5f9081525f805160206117c5833981519152602052604090206001015490565b61041c826103f3565b61042581610a4b565b61042f8383610a58565b50505050565b5f61043e610af9565b905090565b6001600160a01b038116331461046c5760405163334bd91960e11b815260040160405180910390fd5b6104768282610b02565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156104c05750825b90505f8267ffffffffffffffff1660011480156104dc5750303b155b9050811580156104ea575080155b156105085760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561053257845460ff60401b1916600160401b1785555b6001600160a01b0387161580159061055257506001600160a01b03861615155b61055a575f80fd5b6105a060405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060048152602001634d4f564560e01b815250610b7b565b6105e360405180604001604052806008815260200167135bdd995b595b9d60c21b815250604051806040016040528060018152602001603160f81b815250610b91565b6105ed5f88610a58565b50610612866105fe6008600a611625565b61060d906402540be400611633565b610bf0565b831561065857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f805f805160206117858339815191525b6001600160a01b039093165f9081526020939093525050604090205490565b5f61030e82610c24565b5f60608082808083815f805160206117a583398151915280549091501580156106c657506001810154155b61070f5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b610717610c4c565b61071f610c8a565b604080515f80825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b5f9182525f805160206117c5833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f8051602061178583398151915291610337906114f6565b5f336103c68185856109ee565b834211156107ee5760405163313c898160e11b815260048101859052602401610706565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886108588c6001600160a01b03165f9081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6108b282610ca0565b90505f6108c182878787610ccc565b9050896001600160a01b0316816001600160a01b031614610908576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610706565b6109138a8a8a610984565b50505050505050505050565b610928826103f3565b61093181610a4b565b61042f8383610b02565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6104768383836001610cf8565b5f61099c848461093b565b90505f19811461042f57818110156109e057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610706565b61042f84848484035f610cf8565b6001600160a01b038316610a1757604051634b637e8f60e11b81525f6004820152602401610706565b6001600160a01b038216610a405760405163ec442f0560e01b81525f6004820152602401610706565b610476838383610ddc565b610a558133610f15565b50565b5f5f805160206117c5833981519152610a718484610749565b610af0575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610aa63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061030e565b5f91505061030e565b5f61043e610f4e565b5f5f805160206117c5833981519152610b1b8484610749565b15610af0575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061030e565b610b83610fc1565b610b8d828261100c565b5050565b610b99610fc1565b5f805160206117a58339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102610bd284826116a2565b5060038101610be183826116a2565b505f8082556001909101555050565b6001600160a01b038216610c195760405163ec442f0560e01b81525f6004820152602401610706565b610b8d5f8383610ddc565b5f807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00610672565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060915f805160206117a583398151915291610337906114f6565b60605f5f805160206117a5833981519152610326565b5f61030e610cac610af9565b8360405161190160f01b8152600281019290925260228201526042902090565b5f805f80610cdc8888888861105c565b925092509250610cec8282611124565b50909695505050505050565b5f805160206117858339815191526001600160a01b038516610d2f5760405163e602df0560e01b81525f6004820152602401610706565b6001600160a01b038416610d5857604051634a1406b160e11b81525f6004820152602401610706565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610dd557836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610dcc91815260200190565b60405180910390a35b5050505050565b5f805160206117858339815191526001600160a01b038416610e165781816002015f828254610e0b919061175d565b90915550610e869050565b6001600160a01b0384165f9081526020829052604090205482811015610e685760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610706565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316610ea4576002810180548390039055610ec2565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f0791815260200190565b60405180910390a350505050565b610f1f8282610749565b610b8d5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610706565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610f786111dc565b610f80611244565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661100a57604051631afcd79f60e31b815260040160405180910390fd5b565b611014610fc1565b5f805160206117858339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361104d84826116a2565b506004810161042f83826116a2565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109557505f9150600390508261111a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110e6573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661111157505f92506001915082905061111a565b92505f91508190505b9450945094915050565b5f82600381111561113757611137611770565b03611140575050565b600182600381111561115457611154611770565b036111725760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561118657611186611770565b036111a75760405163fce698f760e01b815260048101829052602401610706565b60038260038111156111bb576111bb611770565b03610b8d576040516335e2f38360e21b815260048101829052602401610706565b5f5f805160206117a5833981519152816111f4610c4c565b80519091501561120c57805160209091012092915050565b8154801561121b579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f5f805160206117a58339815191528161125c610c8a565b80519091501561127457805160209091012092915050565b6001820154801561121b579392505050565b5f60208284031215611296575f80fd5b81356001600160e01b0319811681146112ad575f80fd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6112ad60208301846112b4565b80356001600160a01b038116811461130a575f80fd5b919050565b5f8060408385031215611320575f80fd5b611329836112f4565b946020939093013593505050565b5f805f60608486031215611349575f80fd5b611352846112f4565b9250611360602085016112f4565b929592945050506040919091013590565b5f60208284031215611381575f80fd5b5035919050565b5f8060408385031215611399575f80fd5b823591506113a9602084016112f4565b90509250929050565b5f80604083850312156113c3575f80fd5b6113cc836112f4565b91506113a9602084016112f4565b5f602082840312156113ea575f80fd5b6112ad826112f4565b60ff60f81b8816815260e060208201525f61141160e08301896112b4565b828103604084015261142381896112b4565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b8181101561147857835183526020938401939092019160010161145a565b50909b9a5050505050505050505050565b5f805f805f805f60e0888a03121561149f575f80fd5b6114a8886112f4565b96506114b6602089016112f4565b95506040880135945060608801359350608088013560ff811681146114d9575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b600181811c9082168061150a57607f821691505b60208210810361152857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b6001815b600184111561157d578085048111156115615761156161152e565b600184161561156f57908102905b60019390931c928002611546565b935093915050565b5f826115935750600161030e565b8161159f57505f61030e565b81600181146115b557600281146115bf576115db565b600191505061030e565b60ff8411156115d0576115d061152e565b50506001821b61030e565b5060208310610133831016604e8410600b84101617156115fe575081810a61030e565b61160a5f198484611542565b805f190482111561161d5761161d61152e565b029392505050565b5f6112ad60ff841683611585565b808202811582820484141761030e5761030e61152e565b634e487b7160e01b5f52604160045260245ffd5b601f82111561047657805f5260205f20601f840160051c810160208510156116835750805b601f840160051c820191505b81811015610dd5575f815560010161168f565b815167ffffffffffffffff8111156116bc576116bc61164a565b6116d0816116ca84546114f6565b8461165e565b6020601f821160018114611702575f83156116eb5750848201515b5f19600385901b1c1916600184901b178455610dd5565b5f84815260208120601f198516915b828110156117315787850151825560209485019460019092019101611711565b508482101561174e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8082018082111561030e5761030e61152e565b634e487b7160e01b5f52602160045260245ffdfe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a26469706673582212200c213e57e697f2dee37f51b79647b3593da8c247917d58e21e2647bf25597abc64736f6c634300081a0033", + "sourceMap": "299:1259:112:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3443:202:24;;;;;;:::i;:::-;;:::i;:::-;;;470:14:137;;463:22;445:41;;433:2;418:18;3443:202:24;;;;;;;;3011:144:27;;;:::i;:::-;;;;;;;:::i;5505:186::-;;;;;;:::i;:::-;;:::i;4191:152::-;4322:14;;4191:152;;;1645:25:137;;;1633:2;1618:18;4191:152:27;1499:177:137;6251:244:27;;;;;;:::i;:::-;;:::i;4759:191:24:-;;;;;;:::i;:::-;;:::i;5246:136::-;;;;;;:::i;:::-;;:::i;:::-;;1474:82:112;;;1548:1;2920:36:137;;2908:2;2893:18;1474:82:112;2778:184:137;3082:112:28;;;:::i;6348:245:24:-;;;;;;:::i;:::-;;:::i;981:342:112:-;;;;;;:::i;:::-;;:::i;4401:171:27:-;;;;;;:::i;:::-;;:::i;2821:154:28:-;;;;;;:::i;:::-;;:::i;5173:903:31:-;;;:::i;:::-;;;;;;;;;;;;;:::i;3732:207:24:-;;;;;;:::i;:::-;;:::i;3268:148:27:-;;;:::i;2317:49:24:-;;2362:4;2317:49;;4767:178:27;;;;;;:::i;:::-;;:::i;2095:672:28:-;;;;;;:::i;:::-;;:::i;5662:138:24:-;;;;;;:::i;:::-;;:::i;5003:195:27:-;;;;;;:::i;:::-;;:::i;3443:202:24:-;3528:4;-1:-1:-1;;;;;;3551:47:24;;-1:-1:-1;;;3551:47:24;;:87;;-1:-1:-1;;;;;;;;;;1133:40:32;;;3602:36:24;3544:94;3443:202;-1:-1:-1;;3443:202:24:o;3011:144:27:-;3056:13;3081:22;-1:-1:-1;;;;;;;;;;;3106:18:27;3081:43;;3141:1;:7;;3134:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3011:144;:::o;5505:186::-;5578:4;966:10:29;5632:31:27;966:10:29;5648:7:27;5657:5;5632:8;:31::i;:::-;-1:-1:-1;5680:4:27;;5505:186;-1:-1:-1;;;5505:186:27:o;6251:244::-;6338:4;966:10:29;6394:37:27;6410:4;966:10:29;6425:5:27;6394:15;:37::i;:::-;6441:26;6451:4;6457:2;6461:5;6441:9;:26::i;:::-;-1:-1:-1;6484:4:27;;6251:244;-1:-1:-1;;;;6251:244:27:o;4759:191:24:-;4824:7;4919:14;;;-1:-1:-1;;;;;;;;;;;4919:14:24;;;;;:24;;;;4759:191::o;5246:136::-;5320:18;5333:4;5320:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5350:25:::1;5361:4;5367:7;5350:10;:25::i;:::-;;5246:136:::0;;;:::o;3082:112:28:-;3141:7;3167:20;:18;:20::i;:::-;3160:27;;3082:112;:::o;6348:245:24:-;-1:-1:-1;;;;;6441:34:24;;966:10:29;6441:34:24;6437:102;;6498:30;;-1:-1:-1;;;6498:30:24;;;;;;;;;;;6437:102;6549:37;6561:4;6567:18;6549:11;:37::i;:::-;;6348:245;;:::o;981:342:112:-;8870:21:25;4302:15;;-1:-1:-1;;;4302:15:25;;;;4301:16;;4348:14;;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;:16;;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:25;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:25;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:25;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:25;-1:-1:-1;;;5013:22:25;;;4979:67;-1:-1:-1;;;;;1072:20:112;::::1;::::0;;::::1;::::0;:46:::1;;-1:-1:-1::0;;;;;;1096:22:112;::::1;::::0;::::1;1072:46;1064:55;;;::::0;::::1;;1129:32;;;;;;;;;;;;;;-1:-1:-1::0;;;1129:32:112::1;;::::0;::::1;;;;;;;;;;;;;-1:-1:-1::0;;;1129:32:112::1;;::::0;:12:::1;:32::i;:::-;1171:40;;;;;;;;;;;;;;-1:-1:-1::0;;;1171:40:112::1;;::::0;::::1;;;;;;;;;;;;;-1:-1:-1::0;;;1171:40:112::1;;::::0;:23:::1;:40::i;:::-;1221:38;2362:4:24;1252:6:112::0;1221:10:::1;:38::i;:::-;-1:-1:-1::0;1269:47:112::1;1275:8:::0;1299:16:::1;1548:1:::0;1299:2:::1;:16;:::i;:::-;1285:30;::::0;:11:::1;:30;:::i;:::-;1269:5;:47::i;:::-;5070:14:25::0;5066:101;;;5100:23;;-1:-1:-1;;;;5100:23:25;;;5142:14;;-1:-1:-1;7849:50:137;;5142:14:25;;7837:2:137;7822:18;5142:14:25;;;;;;;5066:101;4092:1081;;;;;981:342:112;;:::o;4401:171:27:-;4466:7;;-1:-1:-1;;;;;;;;;;;4510:18:27;-1:-1:-1;;;;;4545:20:27;;;:11;:20;;;;;;;;-1:-1:-1;;4545:20:27;;;;;4401:171::o;2821:154:28:-;2923:7;2949:19;2962:5;2949:12;:19::i;5173:903:31:-;5271:13;5298:18;;5271:13;;;5298:18;5271:13;-1:-1:-1;;;;;;;;;;;5777:13:31;;5511:45;;-1:-1:-1;5777:18:31;:43;;;;-1:-1:-1;5799:16:31;;;;:21;5777:43;5769:77;;;;-1:-1:-1;;;5769:77:31;;8112:2:137;5769:77:31;;;8094:21:137;8151:2;8131:18;;;8124:30;-1:-1:-1;;;8170:18:137;;;8163:51;8231:18;;5769:77:31;;;;;;;;;5908:13;:11;:13::i;:::-;5935:16;:14;:16::i;:::-;6043;;;6027:1;6043:16;;;;;;;;;-1:-1:-1;;;5857:212:31;;;-1:-1:-1;5857:212:31;;-1:-1:-1;5965:13:31;;-1:-1:-1;6000:4:31;;-1:-1:-1;6027:1:31;-1:-1:-1;6043:16:31;-1:-1:-1;5857:212:31;-1:-1:-1;;5173:903:31:o;3732:207:24:-;3809:4;3901:14;;;-1:-1:-1;;;;;;;;;;;3901:14:24;;;;;;;;-1:-1:-1;;;;;3901:31:24;;;;;;;;;;;;;;;3732:207::o;3268:148:27:-;3400:9;3393:16;;3315:13;;-1:-1:-1;;;;;;;;;;;2359:20:27;3393:16;;;:::i;4767:178::-;4836:4;966:10:29;4890:27:27;966:10:29;4907:2:27;4911:5;4890:9;:27::i;2095:672:28:-;2316:8;2298:15;:26;2294:97;;;2347:33;;-1:-1:-1;;;2347:33:28;;;;;1645:25:137;;;1618:18;;2347:33:28;1499:177:137;2294:97:28;2401:18;1277:95;2460:5;2467:7;2476:5;2483:16;2493:5;-1:-1:-1;;;;;1954:16:30;1597:7;1954:16;;;1005:21;1954:16;;;;;:18;;;;;;;;;1537:452;2483:16:28;2432:78;;;;;;8679:25:137;;;;-1:-1:-1;;;;;8740:32:137;;;8720:18;;;8713:60;8809:32;;;;8789:18;;;8782:60;8858:18;;;8851:34;8901:19;;;8894:35;8945:19;;;8938:35;;;8651:19;;2432:78:28;;;;;;;;;;;;2422:89;;;;;;2401:110;;2522:12;2537:28;2554:10;2537:16;:28::i;:::-;2522:43;;2576:14;2593:28;2607:4;2613:1;2616;2619;2593:13;:28::i;:::-;2576:45;;2645:5;-1:-1:-1;;;;;2635:15:28;:6;-1:-1:-1;;;;;2635:15:28;;2631:88;;2673:35;;-1:-1:-1;;;2673:35:28;;-1:-1:-1;;;;;9176:32:137;;;2673:35:28;;;9158:51:137;9245:32;;9225:18;;;9218:60;9131:18;;2673:35:28;8984:300:137;2631:88:28;2729:31;2738:5;2745:7;2754:5;2729:8;:31::i;:::-;2284:483;;;2095:672;;;;;;;:::o;5662:138:24:-;5737:18;5750:4;5737:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5767:26:::1;5779:4;5785:7;5767:11;:26::i;5003:195:27:-:0;-1:-1:-1;;;;;5162:20:27;;;5083:7;5162:20;;;:13;:20;;;;;;;;:29;;;;;;;;;;;;;5003:195::o;10264:128::-;10348:37;10357:5;10364:7;10373:5;10380:4;10348:8;:37::i;11993:477::-;12092:24;12119:25;12129:5;12136:7;12119:9;:25::i;:::-;12092:52;;-1:-1:-1;;12158:16:27;:37;12154:310;;12234:5;12215:16;:24;12211:130;;;12266:60;;-1:-1:-1;;;12266:60:27;;-1:-1:-1;;;;;9509:32:137;;12266:60:27;;;9491:51:137;9558:18;;;9551:34;;;9601:18;;;9594:34;;;9464:18;;12266:60:27;9289:345:137;12211:130:27;12382:57;12391:5;12398:7;12426:5;12407:16;:24;12433:5;12382:8;:57::i;6868:300::-;-1:-1:-1;;;;;6951:18:27;;6947:86;;6992:30;;-1:-1:-1;;;6992:30:27;;7019:1;6992:30;;;9785:51:137;9758:18;;6992:30:27;9639:203:137;6947:86:27;-1:-1:-1;;;;;7046:16:27;;7042:86;;7085:32;;-1:-1:-1;;;7085:32:27;;7114:1;7085:32;;;9785:51:137;9758:18;;7085:32:27;9639:203:137;7042:86:27;7137:24;7145:4;7151:2;7155:5;7137:7;:24::i;4148:103:24:-;4214:30;4225:4;966:10:29;4214::24;:30::i;:::-;4148:103;:::o;7270:387::-;7347:4;-1:-1:-1;;;;;;;;;;;7437:22:24;7445:4;7451:7;7437;:22::i;:::-;7432:219;;7475:8;:14;;;;;;;;;;;-1:-1:-1;;;;;7475:31:24;;;;;;;;;:38;;-1:-1:-1;;7475:38:24;7509:4;7475:38;;;7559:12;966:10:29;;887:96;7559:12:24;-1:-1:-1;;;;;7532:40:24;7550:7;-1:-1:-1;;;;;7532:40:24;7544:4;7532:40;;;;;;;;;;7593:4;7586:11;;;;;7432:219;7635:5;7628:12;;;;;4015:109:31;4068:7;4094:23;:21;:23::i;7892:388:24:-;7970:4;-1:-1:-1;;;;;;;;;;;8059:22:24;8067:4;8073:7;8059;:22::i;:::-;8055:219;;;8131:5;8097:14;;;;;;;;;;;-1:-1:-1;;;;;8097:31:24;;;;;;;;;;:39;;-1:-1:-1;;8097:39:24;;;8155:40;966:10:29;;8097:14:24;;8155:40;;8131:5;8155:40;8216:4;8209:11;;;;;2577:147:27;6931:20:25;:18;:20::i;:::-;2679:38:27::1;2702:5;2709:7;2679:22;:38::i;:::-;2577:147:::0;;:::o;3599:330:31:-;6931:20:25;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;3766:7:31;:14:::1;3776:4:::0;3766:7;:14:::1;:::i;:::-;-1:-1:-1::0;3790:10:31::1;::::0;::::1;:20;3803:7:::0;3790:10;:20:::1;:::i;:::-;-1:-1:-1::0;3891:1:31::1;3875:17:::0;;;3902:16:::1;::::0;;::::1;:20:::0;-1:-1:-1;;3599:330:31:o;8996:208:27:-;-1:-1:-1;;;;;9066:21:27;;9062:91;;9110:32;;-1:-1:-1;;;9110:32:27;;9139:1;9110:32;;;9785:51:137;9758:18;;9110:32:27;9639:203:137;9062:91:27;9162:35;9178:1;9182:7;9191:5;9162:7;:35::i;1259:164:30:-;1319:7;;1005:21;1364:19;886:156;6300:155:31;6441:7;6434:14;;6354:13;;-1:-1:-1;;;;;;;;;;;2839:21:31;6434:14;;;:::i;6682:161::-;6739:13;6764:23;-1:-1:-1;;;;;;;;;;;6790:19:31;2720:156;4946:176;5023:7;5049:66;5082:20;:18;:20::i;:::-;5104:10;3555:4:61;3549:11;-1:-1:-1;;;3573:23:61;;3625:4;3616:14;;3609:39;;;;3677:4;3668:14;;3661:34;3733:4;3718:20;;;3353:401;6803:260:60;6888:7;6908:17;6927:18;6947:16;6967:25;6978:4;6984:1;6987;6990;6967:10;:25::i;:::-;6907:85;;;;;;7002:28;7014:5;7021:8;7002:11;:28::i;:::-;-1:-1:-1;7047:9:60;;6803:260;-1:-1:-1;;;;;;6803:260:60:o;11224:487:27:-;-1:-1:-1;;;;;;;;;;;;;;;;11389:19:27;;11385:89;;11431:32;;-1:-1:-1;;;11431:32:27;;11460:1;11431:32;;;9785:51:137;9758:18;;11431:32:27;9639:203:137;11385:89:27;-1:-1:-1;;;;;11487:21:27;;11483:90;;11531:31;;-1:-1:-1;;;11531:31:27;;11559:1;11531:31;;;9785:51:137;9758:18;;11531:31:27;9639:203:137;11483:90:27;-1:-1:-1;;;;;11582:20:27;;;;;;;:13;;;:20;;;;;;;;:29;;;;;;;;;:37;;;11629:76;;;;11679:7;-1:-1:-1;;;;;11663:31:27;11672:5;-1:-1:-1;;;;;11663:31:27;;11688:5;11663:31;;;;1645:25:137;;1633:2;1618:18;;1499:177;11663:31:27;;;;;;;;11629:76;11322:389;11224:487;;;;:::o;7483:1170::-;-1:-1:-1;;;;;;;;;;;;;;;;7625:18:27;;7621:546;;7779:5;7761:1;:14;;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;7621:546:27;;-1:-1:-1;7621:546:27;;-1:-1:-1;;;;;7837:17:27;;7815:19;7837:17;;;;;;;;;;;7872:19;;;7868:115;;;7918:50;;-1:-1:-1;;;7918:50:27;;-1:-1:-1;;;;;9509:32:137;;7918:50:27;;;9491:51:137;9558:18;;;9551:34;;;9601:18;;;9594:34;;;9464:18;;7918:50:27;9289:345:137;7868:115:27;-1:-1:-1;;;;;8103:17:27;;:11;:17;;;;;;;;;;8123:19;;;;8103:39;;7621:546;-1:-1:-1;;;;;8181:16:27;;8177:429;;8344:14;;;:23;;;;;;;8177:429;;;-1:-1:-1;;;;;8557:15:27;;:11;:15;;;;;;;;;;:24;;;;;;8177:429;8636:2;-1:-1:-1;;;;;8621:25:27;8630:4;-1:-1:-1;;;;;8621:25:27;;8640:5;8621:25;;;;1645::137;;1633:2;1618:18;;1499:177;8621:25:27;;;;;;;;7558:1095;7483:1170;;;:::o;4381:197:24:-;4469:22;4477:4;4483:7;4469;:22::i;:::-;4464:108;;4514:47;;-1:-1:-1;;;4514:47:24;;-1:-1:-1;;;;;12293:32:137;;4514:47:24;;;12275:51:137;12342:18;;;12335:34;;;12248:18;;4514:47:24;12101:274:137;4130:191:31;4185:7;2073:95;4243:17;:15;:17::i;:::-;4262:20;:18;:20::i;:::-;4221:92;;;;;;12639:25:137;;;;12680:18;;12673:34;;;;12723:18;;;12716:34;4284:13:31;12766:18:137;;;12759:34;4307:4:31;12809:19:137;;;12802:61;12611:19;;4221:92:31;;;;;;;;;;;;4211:103;;;;;;4204:110;;4130:191;:::o;7084:141:25:-;8870:21;8560:40;-1:-1:-1;;;8560:40:25;;;;7146:73;;7191:17;;-1:-1:-1;;;7191:17:25;;;;;;;;;;;7146:73;7084:141::o;2730:216:27:-;6931:20:25;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;2895:7:27;:15:::1;2905:5:::0;2895:7;:15:::1;:::i;:::-;-1:-1:-1::0;2920:9:27::1;::::0;::::1;:19;2932:7:::0;2920:9;:19:::1;:::i;5140:1530:60:-:0;5266:7;;;6199:66;6186:79;;6182:164;;;-1:-1:-1;6297:1:60;;-1:-1:-1;6301:30:60;;-1:-1:-1;6333:1:60;6281:54;;6182:164;6457:24;;;6440:14;6457:24;;;;;;;;;13101:25:137;;;13174:4;13162:17;;13142:18;;;13135:45;;;;13196:18;;;13189:34;;;13239:18;;;13232:34;;;6457:24:60;;13073:19:137;;6457:24:60;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6457:24:60;;-1:-1:-1;;6457:24:60;;;-1:-1:-1;;;;;;;6495:20:60;;6491:113;;-1:-1:-1;6547:1:60;;-1:-1:-1;6551:29:60;;-1:-1:-1;6547:1:60;;-1:-1:-1;6531:62:60;;6491:113;6622:6;-1:-1:-1;6630:20:60;;-1:-1:-1;6630:20:60;;-1:-1:-1;5140:1530:60;;;;;;;;;:::o;7196:532::-;7291:20;7282:5;:29;;;;;;;;:::i;:::-;;7278:444;;7196:532;;:::o;7278:444::-;7387:29;7378:5;:38;;;;;;;;:::i;:::-;;7374:348;;7439:23;;-1:-1:-1;;;7439:23:60;;;;;;;;;;;7374:348;7492:35;7483:5;:44;;;;;;;;:::i;:::-;;7479:243;;7550:46;;-1:-1:-1;;;7550:46:60;;;;;1645:25:137;;;1618:18;;7550:46:60;1499:177:137;7479:243:60;7626:30;7617:5;:39;;;;;;;;:::i;:::-;;7613:109;;7679:32;;-1:-1:-1;;;7679:32:60;;;;;1645:25:137;;;1618:18;;7679:32:60;1499:177:137;7058:687:31;7108:7;-1:-1:-1;;;;;;;;;;;7108:7:31;7203:13;:11;:13::i;:::-;7230:18;;7182:34;;-1:-1:-1;7230:22:31;7226:513;;7275:22;;;;;;;;7058:687;-1:-1:-1;;7058:687:31:o;7226:513::-;7572:13;;7603:15;;7599:130;;7645:10;7058:687;-1:-1:-1;;;7058:687:31:o;7599:130::-;7701:13;7694:20;;;;;7058:687;:::o;7966:723::-;8019:7;-1:-1:-1;;;;;;;;;;;8019:7:31;8117:16;:14;:16::i;:::-;8147:21;;8093:40;;-1:-1:-1;8147:25:31;8143:540;;8195:25;;;;;;;;7966:723;-1:-1:-1;;7966:723:31:o;8143:540::-;8507:16;;;;8541:18;;8537:136;;8586:13;7966:723;-1:-1:-1;;;7966:723:31:o;14:286:137:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:137;;209:43;;199:71;;266:1;263;256:12;199:71;289:5;14:286;-1:-1:-1;;;14:286:137:o;497:289::-;539:3;577:5;571:12;604:6;599:3;592:19;660:6;653:4;646:5;642:16;635:4;630:3;626:14;620:47;712:1;705:4;696:6;691:3;687:16;683:27;676:38;775:4;768:2;764:7;759:2;751:6;747:15;743:29;738:3;734:39;730:50;723:57;;;497:289;;;;:::o;791:220::-;940:2;929:9;922:21;903:4;960:45;1001:2;990:9;986:18;978:6;960:45;:::i;1016:173::-;1084:20;;-1:-1:-1;;;;;1133:31:137;;1123:42;;1113:70;;1179:1;1176;1169:12;1113:70;1016:173;;;:::o;1194:300::-;1262:6;1270;1323:2;1311:9;1302:7;1298:23;1294:32;1291:52;;;1339:1;1336;1329:12;1291:52;1362:29;1381:9;1362:29;:::i;:::-;1352:39;1460:2;1445:18;;;;1432:32;;-1:-1:-1;;;1194:300:137:o;1681:374::-;1758:6;1766;1774;1827:2;1815:9;1806:7;1802:23;1798:32;1795:52;;;1843:1;1840;1833:12;1795:52;1866:29;1885:9;1866:29;:::i;:::-;1856:39;;1914:38;1948:2;1937:9;1933:18;1914:38;:::i;:::-;1681:374;;1904:48;;-1:-1:-1;;;2021:2:137;2006:18;;;;1993:32;;1681:374::o;2060:226::-;2119:6;2172:2;2160:9;2151:7;2147:23;2143:32;2140:52;;;2188:1;2185;2178:12;2140:52;-1:-1:-1;2233:23:137;;2060:226;-1:-1:-1;2060:226:137:o;2473:300::-;2541:6;2549;2602:2;2590:9;2581:7;2577:23;2573:32;2570:52;;;2618:1;2615;2608:12;2570:52;2663:23;;;-1:-1:-1;2729:38:137;2763:2;2748:18;;2729:38;:::i;:::-;2719:48;;2473:300;;;;;:::o;2967:260::-;3035:6;3043;3096:2;3084:9;3075:7;3071:23;3067:32;3064:52;;;3112:1;3109;3102:12;3064:52;3135:29;3154:9;3135:29;:::i;:::-;3125:39;;3183:38;3217:2;3206:9;3202:18;3183:38;:::i;3232:186::-;3291:6;3344:2;3332:9;3323:7;3319:23;3315:32;3312:52;;;3360:1;3357;3350:12;3312:52;3383:29;3402:9;3383:29;:::i;3423:1238::-;3829:3;3824;3820:13;3812:6;3808:26;3797:9;3790:45;3871:3;3866:2;3855:9;3851:18;3844:31;3771:4;3898:46;3939:3;3928:9;3924:19;3916:6;3898:46;:::i;:::-;3992:9;3984:6;3980:22;3975:2;3964:9;3960:18;3953:50;4026:33;4052:6;4044;4026:33;:::i;:::-;4090:2;4075:18;;4068:34;;;-1:-1:-1;;;;;4139:32:137;;4133:3;4118:19;;4111:61;4159:3;4188:19;;4181:35;;;4253:22;;;4247:3;4232:19;;4225:51;4325:13;;4347:22;;;4397:2;4423:15;;;;-1:-1:-1;4385:15:137;;;;-1:-1:-1;4466:169:137;4480:6;4477:1;4474:13;4466:169;;;4541:13;;4529:26;;4584:2;4610:15;;;;4575:12;;;;4502:1;4495:9;4466:169;;;-1:-1:-1;4652:3:137;;3423:1238;-1:-1:-1;;;;;;;;;;;3423:1238:137:o;4666:903::-;4777:6;4785;4793;4801;4809;4817;4825;4878:3;4866:9;4857:7;4853:23;4849:33;4846:53;;;4895:1;4892;4885:12;4846:53;4918:29;4937:9;4918:29;:::i;:::-;4908:39;;4966:38;5000:2;4989:9;4985:18;4966:38;:::i;:::-;4956:48;-1:-1:-1;5073:2:137;5058:18;;5045:32;;-1:-1:-1;5174:2:137;5159:18;;5146:32;;-1:-1:-1;5256:3:137;5241:19;;5228:33;5305:4;5292:18;;5280:31;;5270:59;;5325:1;5322;5315:12;5270:59;4666:903;;;;-1:-1:-1;4666:903:137;;;;5348:7;5428:3;5413:19;;5400:33;;-1:-1:-1;5532:3:137;5517:19;;;5504:33;;4666:903;-1:-1:-1;;4666:903:137:o;5574:380::-;5653:1;5649:12;;;;5696;;;5717:61;;5771:4;5763:6;5759:17;5749:27;;5717:61;5824:2;5816:6;5813:14;5793:18;5790:38;5787:161;;5870:10;5865:3;5861:20;5858:1;5851:31;5905:4;5902:1;5895:15;5933:4;5930:1;5923:15;5787:161;;5574:380;;;:::o;5959:127::-;6020:10;6015:3;6011:20;6008:1;6001:31;6051:4;6048:1;6041:15;6075:4;6072:1;6065:15;6091:375;6179:1;6197:5;6211:249;6232:1;6222:8;6219:15;6211:249;;;6282:4;6277:3;6273:14;6267:4;6264:24;6261:50;;;6291:18;;:::i;:::-;6341:1;6331:8;6327:16;6324:49;;;6355:16;;;;6324:49;6438:1;6434:16;;;;;6394:15;;6211:249;;;6091:375;;;;;;:::o;6471:902::-;6520:5;6550:8;6540:80;;-1:-1:-1;6591:1:137;6605:5;;6540:80;6639:4;6629:76;;-1:-1:-1;6676:1:137;6690:5;;6629:76;6721:4;6739:1;6734:59;;;;6807:1;6802:174;;;;6714:262;;6734:59;6764:1;6755:10;;6778:5;;;6802:174;6839:3;6829:8;6826:17;6823:43;;;6846:18;;:::i;:::-;-1:-1:-1;;6902:1:137;6888:16;;6961:5;;6714:262;;7060:2;7050:8;7047:16;7041:3;7035:4;7032:13;7028:36;7022:2;7012:8;7009:16;7004:2;6998:4;6995:12;6991:35;6988:77;6985:203;;;-1:-1:-1;7097:19:137;;;7173:5;;6985:203;7220:42;-1:-1:-1;;7245:8:137;7239:4;7220:42;:::i;:::-;7298:6;7294:1;7290:6;7286:19;7277:7;7274:32;7271:58;;;7309:18;;:::i;:::-;7347:20;;6471:902;-1:-1:-1;;;6471:902:137:o;7378:140::-;7436:5;7465:47;7506:4;7496:8;7492:19;7486:4;7465:47;:::i;7523:168::-;7596:9;;;7627;;7644:15;;;7638:22;;7624:37;7614:71;;7665:18;;:::i;8260:127::-;8321:10;8316:3;8312:20;8309:1;8302:31;8352:4;8349:1;8342:15;8376:4;8373:1;8366:15;9973:518;10075:2;10070:3;10067:11;10064:421;;;10111:5;10108:1;10101:16;10155:4;10152:1;10142:18;10225:2;10213:10;10209:19;10206:1;10202:27;10196:4;10192:38;10261:4;10249:10;10246:20;10243:47;;;-1:-1:-1;10284:4:137;10243:47;10339:2;10334:3;10330:12;10327:1;10323:20;10317:4;10313:31;10303:41;;10394:81;10412:2;10405:5;10402:13;10394:81;;;10471:1;10457:16;;10438:1;10427:13;10394:81;;10667:1299;10793:3;10787:10;10820:18;10812:6;10809:30;10806:56;;;10842:18;;:::i;:::-;10871:97;10961:6;10921:38;10953:4;10947:11;10921:38;:::i;:::-;10915:4;10871:97;:::i;:::-;11017:4;11048:2;11037:14;;11065:1;11060:649;;;;11753:1;11770:6;11767:89;;;-1:-1:-1;11822:19:137;;;11816:26;11767:89;-1:-1:-1;;10624:1:137;10620:11;;;10616:24;10612:29;10602:40;10648:1;10644:11;;;10599:57;11869:81;;11030:930;;11060:649;9920:1;9913:14;;;9957:4;9944:18;;-1:-1:-1;;11096:20:137;;;11214:222;11228:7;11225:1;11222:14;11214:222;;;11310:19;;;11304:26;11289:42;;11417:4;11402:20;;;;11370:1;11358:14;;;;11244:12;11214:222;;;11218:3;11464:6;11455:7;11452:19;11449:201;;;11525:19;;;11519:26;-1:-1:-1;;11608:1:137;11604:14;;;11620:3;11600:24;11596:37;11592:42;11577:58;11562:74;;11449:201;-1:-1:-1;;;;11696:1:137;11680:14;;;11676:22;11663:36;;-1:-1:-1;10667:1299:137:o;11971:125::-;12036:9;;;12057:10;;;12054:36;;;12070:18;;:::i;13277:127::-;13338:10;13333:3;13329:20;13326:1;13319:31;13369:4;13366:1;13359:15;13393:4;13390:1;13383:15", + "linkReferences": {} + }, + "methodIdentifiers": { + "DEFAULT_ADMIN_ROLE()": "a217fddf", + "DOMAIN_SEPARATOR()": "3644e515", + "allowance(address,address)": "dd62ed3e", + "approve(address,uint256)": "095ea7b3", + "balanceOf(address)": "70a08231", + "decimals()": "313ce567", + "eip712Domain()": "84b0196e", + "getRoleAdmin(bytes32)": "248a9ca3", + "grantRole(bytes32,address)": "2f2ff15d", + "hasRole(bytes32,address)": "91d14854", + "initialize(address,address)": "485cc955", + "name()": "06fdde03", + "nonces(address)": "7ecebe00", + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": "d505accf", + "renounceRole(bytes32,address)": "36568abe", + "revokeRole(bytes32,address)": "d547741f", + "supportsInterface(bytes4)": "01ffc9a7", + "symbol()": "95d89b41", + "totalSupply()": "18160ddd", + "transfer(address,uint256)": "a9059cbb", + "transferFrom(address,address,uint256)": "23b872dd" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"name\":\"ERC2612ExpiredSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC2612InvalidSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentNonce\",\"type\":\"uint256\"}],\"name\":\"InvalidAccountNonce\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"EIP712DomainChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip712Domain\",\"outputs\":[{\"internalType\":\"bytes1\",\"name\":\"fields\",\"type\":\"bytes1\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"verifyingContract\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"salt\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"extensions\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_custody\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"ECDSAInvalidSignature()\":[{\"details\":\"The signature derives the `address(0)`.\"}],\"ECDSAInvalidSignatureLength(uint256)\":[{\"details\":\"The signature has an .\"}],\"ECDSAInvalidSignatureS(bytes32)\":[{\"details\":\"The signature has an S value that is in the upper half order.\"}],\"ERC20InsufficientAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failure with the `spender`\\u2019s `allowance`. Used in transfers.\",\"params\":{\"allowance\":\"Amount of tokens a `spender` is allowed to operate with.\",\"needed\":\"Minimum amount required to perform a transfer.\",\"spender\":\"Address that may be allowed to operate on tokens without being their owner.\"}}],\"ERC20InsufficientBalance(address,uint256,uint256)\":[{\"details\":\"Indicates an error related to the current `balance` of a `sender`. Used in transfers.\",\"params\":{\"balance\":\"Current balance for the interacting account.\",\"needed\":\"Minimum amount required to perform a transfer.\",\"sender\":\"Address whose tokens are being transferred.\"}}],\"ERC20InvalidApprover(address)\":[{\"details\":\"Indicates a failure with the `approver` of a token to be approved. Used in approvals.\",\"params\":{\"approver\":\"Address initiating an approval operation.\"}}],\"ERC20InvalidReceiver(address)\":[{\"details\":\"Indicates a failure with the token `receiver`. Used in transfers.\",\"params\":{\"receiver\":\"Address to which tokens are being transferred.\"}}],\"ERC20InvalidSender(address)\":[{\"details\":\"Indicates a failure with the token `sender`. Used in transfers.\",\"params\":{\"sender\":\"Address whose tokens are being transferred.\"}}],\"ERC20InvalidSpender(address)\":[{\"details\":\"Indicates a failure with the `spender` to be approved. Used in approvals.\",\"params\":{\"spender\":\"Address that may be allowed to operate on tokens without being their owner.\"}}],\"ERC2612ExpiredSignature(uint256)\":[{\"details\":\"Permit deadline has expired.\"}],\"ERC2612InvalidSigner(address,address)\":[{\"details\":\"Mismatched signature.\"}],\"InvalidAccountNonce(address,uint256)\":[{\"details\":\"The nonce used for an `account` is not the expected current nonce.\"}],\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"EIP712DomainChanged()\":{\"details\":\"MAY be emitted to signal that the domain could have changed.\"},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. NOTE: If `value` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"constructor\":{\"details\":\"Disables potential implementation exploit\"},\"decimals()\":{\"details\":\"Returns the number of decimals\"},\"eip712Domain()\":{\"details\":\"See {IERC-5267}.\"},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"initialize(address,address)\":{\"details\":\"Initializes the contract with initial parameters.\",\"params\":{\"_custody\":\"The address of the custody account.\",\"_owner\":\"The address of the owner who receives default admin role.\"}},\"name()\":{\"details\":\"Returns the name of the token.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `value`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `value`. - the caller must have allowance for ``from``'s tokens of at least `value`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"decimals()\":{\"notice\":\"decimals is set to 8, following the Movement network standard decimals\"},\"initialize(address,address)\":{\"notice\":\"The ERC20 token is named \\\"Movement\\\" with symbol \\\"MOVE\\\".EIP712 domain version is set to \\\"1\\\" for signatures.The owner is granted the `DEFAULT_ADMIN_ROLE`.10 billion MOVE tokens are minted to the owner's address.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/token/MOVEToken.sol\":\"MOVEToken\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@createx/=lib/createx/src/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@safe-smart-account/=lib/safe-smart-account/\",\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":murky/=lib/murky/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/\",\":openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/\",\":safe-smart-account/=lib/safe-smart-account/\",\":solady/=lib/createx/lib/solady/\",\":solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\":{\"keccak256\":\"0x6662ec4e5cefca03eeadd073e9469df8d2944bb2ee8ec8f7622c2c46aab5f225\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4d8544c6f8daa4d1bc215c6a72fe0acdb748664a105b0e5efc19295667521d45\",\"dweb:/ipfs/QmdGWqdnXT8S3RgCR6aV8XHZrsybieMQLLnug1NtpSjEXN\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609\",\"dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol\":{\"keccak256\":\"0x9a1766b1921bf91b3e61eb53c7a6e70725254befd4bdcbbcd3af40bd9f66856f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29bf2fa41a172086a665c9738377b93655aa4b1ffda9fe839c8bdf646f185040\",\"dweb:/ipfs/QmeB21qDuo8WPQSrqXJbQmWHKsdeocGNSUWLhCwniVejrt\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol\":{\"keccak256\":\"0x8a97653aeba40e9f0c2e8df1a1379b29b927b6dc3534040c668e71ad9ae89d88\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e529c294c9d634eb68a1e4aeb66eb8381de5a08ccd2c0bfeebd48a6b28fcff7\",\"dweb:/ipfs/QmWCezuxfZb68nM3Hs6XzQNNiW7VJsymU4sajy2DW1CKbp\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9\",\"dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol\":{\"keccak256\":\"0x778f4a1546a1c6c726ecc8e2348a2789690fb8f26e12bd9d89537669167b79a4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://851d3dfe724e918ff0a064b206e1ef46b27ab0df2aa2c8af976973a22ef59827\",\"dweb:/ipfs/Qmd4wb7zX8ueYhMVBy5PJjfsANK3Ra3pKPN7qQkNsdwGHn\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol\":{\"keccak256\":\"0x85462422a22578744581e012e9aa0a391958cb360288b0b63f29bf0431d70327\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2bc529e2b9b28da5d26da451058250d85afcaa3c5083ee273ac68fa6bf956b78\",\"dweb:/ipfs/Qmd3Aq59ztmoVmHigsaR4YjkXWKERVpjfQ4a2PHk7Ke6Rx\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol\":{\"keccak256\":\"0xdaba3f7c42c55b2896353f32bd27d4d5f8bae741b3b05d4c53f67abc4dc47ce8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1fa2e61141c602510bcd2cd936ed9561922ac8772a9b9c9a9db091a74e354a45\",\"dweb:/ipfs/QmcHQDDoEBwJmwUbzoVkytvJsBx3KVHYFFnDkvRGWh9Wmh\"]},\"lib/openzeppelin-contracts/contracts/access/IAccessControl.sol\":{\"keccak256\":\"0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1fd2f35495652e57e3f99bc6c510bc5f7dd398a176ea2e72d8ed730aebc6ca26\",\"dweb:/ipfs/QmTQV6X4gkikTib49cho5iDX3JvSQbdsoEChoDwrk3CbbH\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol\":{\"keccak256\":\"0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a\",\"dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP\"]},\"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol\":{\"keccak256\":\"0x60c65f701957fdd6faea1acb0bb45825791d473693ed9ecb34726fdfaa849dd7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ea290300e0efc4d901244949dc4d877fd46e6c5e43dc2b26620e8efab3ab803f\",\"dweb:/ipfs/QmcLLJppxKeJWqHxE2CUkcfhuRTgHSn8J4kijcLa5MYhSt\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ea104e577e63faea3b69c415637e99e755dcbf64c5833d7140c35a714d6d90c\",\"dweb:/ipfs/Qmau6x4Ns9XdyynRCNNp3RhLqijJjFm7z5fyZazfYFGYdq\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0xaa761817f6cd7892fcf158b3c776b34551cde36f48ff9703d53898bc45a94ea2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ad7c8d4d08938c8dfc43d75a148863fb324b80cf53e0a36f7e5a4ac29008850\",\"dweb:/ipfs/QmcrhfPgVNf5mkdhQvy1pMv51TFokD3Y4Wa5WZhFqVh8UV\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"keccak256\":\"0x6008dabfe393240d73d7dd7688033f72740d570aa422254d29a7dce8568f3aff\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f5196ec75139918c6c7bb4251b36395e668f1fa6d206beba7e7520e74913940d\",\"dweb:/ipfs/QmSyqjksXxmm2mCG6qRd1yuwLykypkSVBbnBnGqJRcuJMi\"]},\"lib/openzeppelin-contracts/contracts/utils/Strings.sol\":{\"keccak256\":\"0x55f102ea785d8399c0e58d1108e2d289506dde18abc6db1b7f68c1f9f9bc5792\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e52e0a7765c943ef14e5bcf11e46e6139fa044be564881378349236bf2e3453\",\"dweb:/ipfs/QmZEeeXoFPW47amyP35gfzomF9DixqqTEPwzBakv6cZw6i\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0xeed0a08b0b091f528356cbc7245891a4c748682d4f6a18055e8e6ca77d12a6cf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba80ba06c8e6be852847e4c5f4492cef801feb6558ae09ed705ff2e04ea8b13c\",\"dweb:/ipfs/QmXRJDv3xHLVQCVXg1ZvR35QS9sij5y9NDWYzMfUfAdTHF\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol\":{\"keccak256\":\"0xba333517a3add42cd35fe877656fc3dfcc9de53baa4f3aabbd6d12a92e4ea435\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2ceacff44c0fdc81e48e0e0b1db87a2076d3c1fb497341de077bf1da9f6b406c\",\"dweb:/ipfs/QmRUo1muMRAewxrKQ7TkXUtknyRoR57AyEkoPpiuZQ8FzX\"]},\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://87b3541437c8c443ccd36795e56a338ed12855eec17f8da624511b8d1a7e14df\",\"dweb:/ipfs/QmeJQCtZrQjtJLr6u7ZHWeH3pBnjtLWzvRrKViAi7UZqxL\"]},\"lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0x005ec64c6313f0555d59e278f9a7a5ab2db5bdc72a027f255a37c327af1ec02d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4ece9f0b9c8daca08c76b6b5405a6446b6f73b3a15fab7ff56e296cbd4a2c875\",\"dweb:/ipfs/QmQyRpyPRL5SQuAgj6SHmbir3foX65FJjbVTTQrA2EFg6L\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0x5f7e4076e175393767754387c962926577f1660dd9b810187b9002407656be72\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7d533a1c97cd43a57cd9c465f7ee8dd0e39ae93a8fb8ff8e5303a356b081cdcc\",\"dweb:/ipfs/QmVBEei6aTnvYNZp2CHYVNKyZS4q1KkjANfY39WVXZXVoT\"]},\"src/token/MOVEToken.sol\":{\"keccak256\":\"0x907babd7e2db7867a9401ab8edcecd579ad7db099ae4693a27e052887d91eb22\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a87e3b44d5e5409f0695ca2057be132b02b12a6cfa3d95a1a69382458e16b20a\",\"dweb:/ipfs/QmPNA8kiRGr3jR4ngz8UeKLUM7QitN4J5xNbxxWYNncV9H\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.26+commit.8a97fa7a" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "type": "error", + "name": "AccessControlBadConfirmation" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "type": "error", + "name": "AccessControlUnauthorizedAccount" + }, + { + "inputs": [], + "type": "error", + "name": "ECDSAInvalidSignature" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "type": "error", + "name": "ECDSAInvalidSignatureLength" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "type": "error", + "name": "ECDSAInvalidSignatureS" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "type": "error", + "name": "ERC20InsufficientAllowance" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "type": "error", + "name": "ERC20InsufficientBalance" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "type": "error", + "name": "ERC20InvalidApprover" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "type": "error", + "name": "ERC20InvalidReceiver" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "type": "error", + "name": "ERC20InvalidSender" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "type": "error", + "name": "ERC20InvalidSpender" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "type": "error", + "name": "ERC2612ExpiredSignature" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "type": "error", + "name": "ERC2612InvalidSigner" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "currentNonce", + "type": "uint256" + } + ], + "type": "error", + "name": "InvalidAccountNonce" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidInitialization" + }, + { + "inputs": [], + "type": "error", + "name": "NotInitializing" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "spender", + "type": "address", + "indexed": true + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256", + "indexed": false + } + ], + "type": "event", + "name": "Approval", + "anonymous": false + }, + { + "inputs": [], + "type": "event", + "name": "EIP712DomainChanged", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "version", + "type": "uint64", + "indexed": false + } + ], + "type": "event", + "name": "Initialized", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32", + "indexed": true + }, + { + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true + }, + { + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32", + "indexed": true + } + ], + "type": "event", + "name": "RoleAdminChanged", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32", + "indexed": true + }, + { + "internalType": "address", + "name": "account", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "sender", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "RoleGranted", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32", + "indexed": true + }, + { + "internalType": "address", + "name": "account", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "sender", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "RoleRevoked", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "to", + "type": "address", + "indexed": true + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256", + "indexed": false + } + ], + "type": "event", + "name": "Transfer", + "anonymous": false + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function", + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function", + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [], + "stateMutability": "pure", + "type": "function", + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ] + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function", + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "grantRole" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function", + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_custody", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "initialize" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function", + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "permit" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "renounceRole" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "revokeRole" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function", + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "DOMAIN_SEPARATOR()": { + "details": "Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}." + }, + "allowance(address,address)": { + "details": "See {IERC20-allowance}." + }, + "approve(address,uint256)": { + "details": "See {IERC20-approve}. NOTE: If `value` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address." + }, + "balanceOf(address)": { + "details": "See {IERC20-balanceOf}." + }, + "constructor": { + "details": "Disables potential implementation exploit" + }, + "decimals()": { + "details": "Returns the number of decimals" + }, + "eip712Domain()": { + "details": "See {IERC-5267}." + }, + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "initialize(address,address)": { + "details": "Initializes the contract with initial parameters.", + "params": { + "_custody": "The address of the custody account.", + "_owner": "The address of the owner who receives default admin role." + } + }, + "name()": { + "details": "Returns the name of the token." + }, + "nonces(address)": { + "details": "Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times." + }, + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": { + "details": "Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above." + }, + "renounceRole(bytes32,address)": { + "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event." + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event." + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + }, + "symbol()": { + "details": "Returns the symbol of the token, usually a shorter version of the name." + }, + "totalSupply()": { + "details": "See {IERC20-totalSupply}." + }, + "transfer(address,uint256)": { + "details": "See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `value`." + }, + "transferFrom(address,address,uint256)": { + "details": "See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `value`. - the caller must have allowance for ``from``'s tokens of at least `value`." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "decimals()": { + "notice": "decimals is set to 8, following the Movement network standard decimals" + }, + "initialize(address,address)": { + "notice": "The ERC20 token is named \"Movement\" with symbol \"MOVE\".EIP712 domain version is set to \"1\" for signatures.The owner is granted the `DEFAULT_ADMIN_ROLE`.10 billion MOVE tokens are minted to the owner's address." + } + }, + "version": 1 + } + }, + "settings": { + "remappings": [ + "@createx/=lib/createx/src/", + "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", + "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", + "@safe-smart-account/=lib/safe-smart-account/", + "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", + "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", + "forge-std/=lib/forge-std/src/", + "murky/=lib/murky/", + "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", + "openzeppelin-contracts/=lib/openzeppelin-contracts/", + "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", + "openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/", + "safe-smart-account/=lib/safe-smart-account/", + "solady/=lib/createx/lib/solady/", + "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/", + "solmate/=lib/solmate/src/" + ], + "optimizer": { + "enabled": true, + "runs": 200 + }, + "metadata": { + "bytecodeHash": "ipfs" + }, + "compilationTarget": { + "src/token/MOVEToken.sol": "MOVEToken" + }, + "evmVersion": "cancun", + "libraries": {} + }, + "sources": { + "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol": { + "keccak256": "0x6662ec4e5cefca03eeadd073e9469df8d2944bb2ee8ec8f7622c2c46aab5f225", + "urls": [ + "bzz-raw://4d8544c6f8daa4d1bc215c6a72fe0acdb748664a105b0e5efc19295667521d45", + "dweb:/ipfs/QmdGWqdnXT8S3RgCR6aV8XHZrsybieMQLLnug1NtpSjEXN" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": { + "keccak256": "0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b", + "urls": [ + "bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609", + "dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol": { + "keccak256": "0x9a1766b1921bf91b3e61eb53c7a6e70725254befd4bdcbbcd3af40bd9f66856f", + "urls": [ + "bzz-raw://29bf2fa41a172086a665c9738377b93655aa4b1ffda9fe839c8bdf646f185040", + "dweb:/ipfs/QmeB21qDuo8WPQSrqXJbQmWHKsdeocGNSUWLhCwniVejrt" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol": { + "keccak256": "0x8a97653aeba40e9f0c2e8df1a1379b29b927b6dc3534040c668e71ad9ae89d88", + "urls": [ + "bzz-raw://6e529c294c9d634eb68a1e4aeb66eb8381de5a08ccd2c0bfeebd48a6b28fcff7", + "dweb:/ipfs/QmWCezuxfZb68nM3Hs6XzQNNiW7VJsymU4sajy2DW1CKbp" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": { + "keccak256": "0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397", + "urls": [ + "bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9", + "dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol": { + "keccak256": "0x778f4a1546a1c6c726ecc8e2348a2789690fb8f26e12bd9d89537669167b79a4", + "urls": [ + "bzz-raw://851d3dfe724e918ff0a064b206e1ef46b27ab0df2aa2c8af976973a22ef59827", + "dweb:/ipfs/Qmd4wb7zX8ueYhMVBy5PJjfsANK3Ra3pKPN7qQkNsdwGHn" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol": { + "keccak256": "0x85462422a22578744581e012e9aa0a391958cb360288b0b63f29bf0431d70327", + "urls": [ + "bzz-raw://2bc529e2b9b28da5d26da451058250d85afcaa3c5083ee273ac68fa6bf956b78", + "dweb:/ipfs/Qmd3Aq59ztmoVmHigsaR4YjkXWKERVpjfQ4a2PHk7Ke6Rx" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol": { + "keccak256": "0xdaba3f7c42c55b2896353f32bd27d4d5f8bae741b3b05d4c53f67abc4dc47ce8", + "urls": [ + "bzz-raw://1fa2e61141c602510bcd2cd936ed9561922ac8772a9b9c9a9db091a74e354a45", + "dweb:/ipfs/QmcHQDDoEBwJmwUbzoVkytvJsBx3KVHYFFnDkvRGWh9Wmh" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol": { + "keccak256": "0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41", + "urls": [ + "bzz-raw://1fd2f35495652e57e3f99bc6c510bc5f7dd398a176ea2e72d8ed730aebc6ca26", + "dweb:/ipfs/QmTQV6X4gkikTib49cho5iDX3JvSQbdsoEChoDwrk3CbbH" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol": { + "keccak256": "0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92", + "urls": [ + "bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a", + "dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol": { + "keccak256": "0x60c65f701957fdd6faea1acb0bb45825791d473693ed9ecb34726fdfaa849dd7", + "urls": [ + "bzz-raw://ea290300e0efc4d901244949dc4d877fd46e6c5e43dc2b26620e8efab3ab803f", + "dweb:/ipfs/QmcLLJppxKeJWqHxE2CUkcfhuRTgHSn8J4kijcLa5MYhSt" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { + "keccak256": "0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70", + "urls": [ + "bzz-raw://0ea104e577e63faea3b69c415637e99e755dcbf64c5833d7140c35a714d6d90c", + "dweb:/ipfs/Qmau6x4Ns9XdyynRCNNp3RhLqijJjFm7z5fyZazfYFGYdq" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "keccak256": "0xaa761817f6cd7892fcf158b3c776b34551cde36f48ff9703d53898bc45a94ea2", + "urls": [ + "bzz-raw://0ad7c8d4d08938c8dfc43d75a148863fb324b80cf53e0a36f7e5a4ac29008850", + "dweb:/ipfs/QmcrhfPgVNf5mkdhQvy1pMv51TFokD3Y4Wa5WZhFqVh8UV" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": { + "keccak256": "0x6008dabfe393240d73d7dd7688033f72740d570aa422254d29a7dce8568f3aff", + "urls": [ + "bzz-raw://f5196ec75139918c6c7bb4251b36395e668f1fa6d206beba7e7520e74913940d", + "dweb:/ipfs/QmSyqjksXxmm2mCG6qRd1yuwLykypkSVBbnBnGqJRcuJMi" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Strings.sol": { + "keccak256": "0x55f102ea785d8399c0e58d1108e2d289506dde18abc6db1b7f68c1f9f9bc5792", + "urls": [ + "bzz-raw://6e52e0a7765c943ef14e5bcf11e46e6139fa044be564881378349236bf2e3453", + "dweb:/ipfs/QmZEeeXoFPW47amyP35gfzomF9DixqqTEPwzBakv6cZw6i" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": { + "keccak256": "0xeed0a08b0b091f528356cbc7245891a4c748682d4f6a18055e8e6ca77d12a6cf", + "urls": [ + "bzz-raw://ba80ba06c8e6be852847e4c5f4492cef801feb6558ae09ed705ff2e04ea8b13c", + "dweb:/ipfs/QmXRJDv3xHLVQCVXg1ZvR35QS9sij5y9NDWYzMfUfAdTHF" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol": { + "keccak256": "0xba333517a3add42cd35fe877656fc3dfcc9de53baa4f3aabbd6d12a92e4ea435", + "urls": [ + "bzz-raw://2ceacff44c0fdc81e48e0e0b1db87a2076d3c1fb497341de077bf1da9f6b406c", + "dweb:/ipfs/QmRUo1muMRAewxrKQ7TkXUtknyRoR57AyEkoPpiuZQ8FzX" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": { + "keccak256": "0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b", + "urls": [ + "bzz-raw://87b3541437c8c443ccd36795e56a338ed12855eec17f8da624511b8d1a7e14df", + "dweb:/ipfs/QmeJQCtZrQjtJLr6u7ZHWeH3pBnjtLWzvRrKViAi7UZqxL" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": { + "keccak256": "0x005ec64c6313f0555d59e278f9a7a5ab2db5bdc72a027f255a37c327af1ec02d", + "urls": [ + "bzz-raw://4ece9f0b9c8daca08c76b6b5405a6446b6f73b3a15fab7ff56e296cbd4a2c875", + "dweb:/ipfs/QmQyRpyPRL5SQuAgj6SHmbir3foX65FJjbVTTQrA2EFg6L" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol": { + "keccak256": "0x5f7e4076e175393767754387c962926577f1660dd9b810187b9002407656be72", + "urls": [ + "bzz-raw://7d533a1c97cd43a57cd9c465f7ee8dd0e39ae93a8fb8ff8e5303a356b081cdcc", + "dweb:/ipfs/QmVBEei6aTnvYNZp2CHYVNKyZS4q1KkjANfY39WVXZXVoT" + ], + "license": "MIT" + }, + "src/token/MOVEToken.sol": { + "keccak256": "0x907babd7e2db7867a9401ab8edcecd579ad7db099ae4693a27e052887d91eb22", + "urls": [ + "bzz-raw://a87e3b44d5e5409f0695ca2057be132b02b12a6cfa3d95a1a69382458e16b20a", + "dweb:/ipfs/QmPNA8kiRGr3jR4ngz8UeKLUM7QitN4J5xNbxxWYNncV9H" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": {} + }, + "ast": { + "absolutePath": "src/token/MOVEToken.sol", + "id": 56720, + "exportedSymbols": { + "AccessControlUpgradeable": [ + 39385 + ], + "ERC20PermitUpgradeable": [ + 40607 + ], + "MOVEToken": [ + 56719 + ] + }, + "nodeType": "SourceUnit", + "src": "32:1526:112", + "nodes": [ + { + "id": 56640, + "nodeType": "PragmaDirective", + "src": "32:24:112", + "nodes": [], + "literals": [ + "solidity", + "^", + "0.8", + ".19" + ] + }, + { + "id": 56642, + "nodeType": "ImportDirective", + "src": "58:125:112", + "nodes": [], + "absolutePath": "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol", + "file": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol", + "nameLocation": "-1:-1:-1", + "scope": 56720, + "sourceUnit": 40608, + "symbolAliases": [ + { + "foreign": { + "id": 56641, + "name": "ERC20PermitUpgradeable", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 40607, + "src": "66:22:112", + "typeDescriptions": {} + }, + "nameLocation": "-1:-1:-1" + } + ], + "unitAlias": "" + }, + { + "id": 56644, + "nodeType": "ImportDirective", + "src": "184:113:112", + "nodes": [], + "absolutePath": "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol", + "file": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol", + "nameLocation": "-1:-1:-1", + "scope": 56720, + "sourceUnit": 39386, + "symbolAliases": [ + { + "foreign": { + "id": 56643, + "name": "AccessControlUpgradeable", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 39385, + "src": "192:24:112", + "typeDescriptions": {} + }, + "nameLocation": "-1:-1:-1" + } + ], + "unitAlias": "" + }, + { + "id": 56719, + "nodeType": "ContractDefinition", + "src": "299:1259:112", + "nodes": [ + { + "id": 56656, + "nodeType": "FunctionDefinition", + "src": "447:39:112", + "nodes": [], + "body": { + "id": 56655, + "nodeType": "Block", + "src": "461:25:112", + "nodes": [], + "statements": [ + { + "expression": { + "arguments": [], + "expression": { + "argumentTypes": [], + "id": 56652, + "name": "_disableInitializers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 39607, + "src": "462:20:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_nonpayable$__$returns$__$", + "typeString": "function ()" + } + }, + "id": 56653, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "462:22:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 56654, + "nodeType": "ExpressionStatement", + "src": "462:22:112" + } + ] + }, + "documentation": { + "id": 56649, + "nodeType": "StructuredDocumentation", + "src": "377:65:112", + "text": " @dev Disables potential implementation exploit" + }, + "implemented": true, + "kind": "constructor", + "modifiers": [], + "name": "", + "nameLocation": "-1:-1:-1", + "parameters": { + "id": 56650, + "nodeType": "ParameterList", + "parameters": [], + "src": "458:2:112" + }, + "returnParameters": { + "id": 56651, + "nodeType": "ParameterList", + "parameters": [], + "src": "461:0:112" + }, + "scope": 56719, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + { + "id": 56708, + "nodeType": "FunctionDefinition", + "src": "981:342:112", + "nodes": [], + "body": { + "id": 56707, + "nodeType": "Block", + "src": "1054:269:112", + "nodes": [], + "statements": [ + { + "expression": { + "arguments": [ + { + "commonType": { + "typeIdentifier": "t_bool", + "typeString": "bool" + }, + "id": 56679, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "commonType": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "id": 56672, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "id": 56667, + "name": "_owner", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 56659, + "src": "1072:6:112", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "nodeType": "BinaryOperation", + "operator": "!=", + "rightExpression": { + "arguments": [ + { + "hexValue": "30", + "id": 56670, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1090:1:112", + "typeDescriptions": { + "typeIdentifier": "t_rational_0_by_1", + "typeString": "int_const 0" + }, + "value": "0" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_rational_0_by_1", + "typeString": "int_const 0" + } + ], + "id": 56669, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "1082:7:112", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 56668, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "1082:7:112", + "typeDescriptions": {} + } + }, + "id": 56671, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1082:10:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "src": "1072:20:112", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "nodeType": "BinaryOperation", + "operator": "&&", + "rightExpression": { + "commonType": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "id": 56678, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "id": 56673, + "name": "_custody", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 56661, + "src": "1096:8:112", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "nodeType": "BinaryOperation", + "operator": "!=", + "rightExpression": { + "arguments": [ + { + "hexValue": "30", + "id": 56676, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1116:1:112", + "typeDescriptions": { + "typeIdentifier": "t_rational_0_by_1", + "typeString": "int_const 0" + }, + "value": "0" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_rational_0_by_1", + "typeString": "int_const 0" + } + ], + "id": 56675, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "1108:7:112", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 56674, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "1108:7:112", + "typeDescriptions": {} + } + }, + "id": 56677, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1108:10:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "src": "1096:22:112", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "src": "1072:46:112", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + ], + "id": 56666, + "name": "require", + "nodeType": "Identifier", + "overloadedDeclarations": [ + -18, + -18, + -18 + ], + "referencedDeclaration": -18, + "src": "1064:7:112", + "typeDescriptions": { + "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", + "typeString": "function (bool) pure" + } + }, + "id": 56680, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1064:55:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 56681, + "nodeType": "ExpressionStatement", + "src": "1064:55:112" + }, + { + "expression": { + "arguments": [ + { + "hexValue": "4d6f76656d656e74", + "id": 56683, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1142:10:112", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252", + "typeString": "literal_string \"Movement\"" + }, + "value": "Movement" + }, + { + "hexValue": "4d4f5645", + "id": 56684, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1154:6:112", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_94304e8d07ec49123c30284d16c4a1082e90258cc0faf510314d9c3808edcda0", + "typeString": "literal_string \"MOVE\"" + }, + "value": "MOVE" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252", + "typeString": "literal_string \"Movement\"" + }, + { + "typeIdentifier": "t_stringliteral_94304e8d07ec49123c30284d16c4a1082e90258cc0faf510314d9c3808edcda0", + "typeString": "literal_string \"MOVE\"" + } + ], + "id": 56682, + "name": "__ERC20_init", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 39889, + "src": "1129:12:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$", + "typeString": "function (string memory,string memory)" + } + }, + "id": 56685, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1129:32:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 56686, + "nodeType": "ExpressionStatement", + "src": "1129:32:112" + }, + { + "expression": { + "arguments": [ + { + "hexValue": "4d6f76656d656e74", + "id": 56688, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1195:10:112", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252", + "typeString": "literal_string \"Movement\"" + }, + "value": "Movement" + }, + { + "hexValue": "31", + "id": 56689, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1207:3:112", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "typeString": "literal_string \"1\"" + }, + "value": "1" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_stringliteral_76cd1e2e4e245339bcdd0e0d14f4067a3f0952012fc7c5331fdec600bb235252", + "typeString": "literal_string \"Movement\"" + }, + { + "typeIdentifier": "t_stringliteral_c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "typeString": "literal_string \"1\"" + } + ], + "id": 56687, + "name": "__EIP712_init_unchained", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 40861, + "src": "1171:23:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$", + "typeString": "function (string memory,string memory)" + } + }, + "id": 56690, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1171:40:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 56691, + "nodeType": "ExpressionStatement", + "src": "1171:40:112" + }, + { + "expression": { + "arguments": [ + { + "id": 56693, + "name": "DEFAULT_ADMIN_ROLE", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 39051, + "src": "1232:18:112", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + }, + { + "id": 56694, + "name": "_owner", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 56659, + "src": "1252:6:112", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + }, + { + "typeIdentifier": "t_address", + "typeString": "address" + } + ], + "id": 56692, + "name": "_grantRole", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 39338, + "src": "1221:10:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$_t_bool_$", + "typeString": "function (bytes32,address) returns (bool)" + } + }, + "id": 56695, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1221:38:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "id": 56696, + "nodeType": "ExpressionStatement", + "src": "1221:38:112" + }, + { + "expression": { + "arguments": [ + { + "id": 56698, + "name": "_custody", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 56661, + "src": "1275:8:112", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + { + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "id": 56704, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "hexValue": "3130303030303030303030", + "id": 56699, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1285:11:112", + "typeDescriptions": { + "typeIdentifier": "t_rational_10000000000_by_1", + "typeString": "int_const 10000000000" + }, + "value": "10000000000" + }, + "nodeType": "BinaryOperation", + "operator": "*", + "rightExpression": { + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "id": 56703, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "hexValue": "3130", + "id": 56700, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1299:2:112", + "typeDescriptions": { + "typeIdentifier": "t_rational_10_by_1", + "typeString": "int_const 10" + }, + "value": "10" + }, + "nodeType": "BinaryOperation", + "operator": "**", + "rightExpression": { + "arguments": [], + "expression": { + "argumentTypes": [], + "id": 56701, + "name": "decimals", + "nodeType": "Identifier", + "overloadedDeclarations": [ + 56718 + ], + "referencedDeclaration": 56718, + "src": "1305:8:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_pure$__$returns$_t_uint8_$", + "typeString": "function () pure returns (uint8)" + } + }, + "id": 56702, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1305:10:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_uint8", + "typeString": "uint8" + } + }, + "src": "1299:16:112", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "src": "1285:30:112", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "id": 56697, + "name": "_mint", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 40270, + "src": "1269:5:112", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$__$", + "typeString": "function (address,uint256)" + } + }, + "id": 56705, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "1269:47:112", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 56706, + "nodeType": "ExpressionStatement", + "src": "1269:47:112" + } + ] + }, + "documentation": { + "id": 56657, + "nodeType": "StructuredDocumentation", + "src": "492:484:112", + "text": " @dev Initializes the contract with initial parameters.\n @param _owner The address of the owner who receives default admin role.\n @param _custody The address of the custody account.\n @notice The ERC20 token is named \"Movement\" with symbol \"MOVE\".\n @notice EIP712 domain version is set to \"1\" for signatures.\n @notice The owner is granted the `DEFAULT_ADMIN_ROLE`.\n @notice 10 billion MOVE tokens are minted to the owner's address." + }, + "functionSelector": "485cc955", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "id": 56664, + "kind": "modifierInvocation", + "modifierName": { + "id": 56663, + "name": "initializer", + "nameLocations": [ + "1042:11:112" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 39493, + "src": "1042:11:112" + }, + "nodeType": "ModifierInvocation", + "src": "1042:11:112" + } + ], + "name": "initialize", + "nameLocation": "990:10:112", + "parameters": { + "id": 56662, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 56659, + "mutability": "mutable", + "name": "_owner", + "nameLocation": "1009:6:112", + "nodeType": "VariableDeclaration", + "scope": 56708, + "src": "1001:14:112", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": { + "id": 56658, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "1001:7:112", + "stateMutability": "nonpayable", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 56661, + "mutability": "mutable", + "name": "_custody", + "nameLocation": "1025:8:112", + "nodeType": "VariableDeclaration", + "scope": 56708, + "src": "1017:16:112", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": { + "id": 56660, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "1017:7:112", + "stateMutability": "nonpayable", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + } + ], + "src": "1000:34:112" + }, + "returnParameters": { + "id": 56665, + "nodeType": "ParameterList", + "parameters": [], + "src": "1054:0:112" + }, + "scope": 56719, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + { + "id": 56718, + "nodeType": "FunctionDefinition", + "src": "1474:82:112", + "nodes": [], + "body": { + "id": 56717, + "nodeType": "Block", + "src": "1531:25:112", + "nodes": [], + "statements": [ + { + "expression": { + "hexValue": "38", + "id": 56715, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "1548:1:112", + "typeDescriptions": { + "typeIdentifier": "t_rational_8_by_1", + "typeString": "int_const 8" + }, + "value": "8" + }, + "functionReturnParameters": 56714, + "id": 56716, + "nodeType": "Return", + "src": "1541:8:112" + } + ] + }, + "baseFunctions": [ + 39958 + ], + "documentation": { + "id": 56709, + "nodeType": "StructuredDocumentation", + "src": "1329:140:112", + "text": " @dev Returns the number of decimals\n @notice decimals is set to 8, following the Movement network standard decimals" + }, + "functionSelector": "313ce567", + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "decimals", + "nameLocation": "1483:8:112", + "overrides": { + "id": 56711, + "nodeType": "OverrideSpecifier", + "overrides": [], + "src": "1506:8:112" + }, + "parameters": { + "id": 56710, + "nodeType": "ParameterList", + "parameters": [], + "src": "1491:2:112" + }, + "returnParameters": { + "id": 56714, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 56713, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "scope": 56718, + "src": "1524:5:112", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint8", + "typeString": "uint8" + }, + "typeName": { + "id": 56712, + "name": "uint8", + "nodeType": "ElementaryTypeName", + "src": "1524:5:112", + "typeDescriptions": { + "typeIdentifier": "t_uint8", + "typeString": "uint8" + } + }, + "visibility": "internal" + } + ], + "src": "1523:7:112" + }, + "scope": 56719, + "stateMutability": "pure", + "virtual": false, + "visibility": "public" + } + ], + "abstract": false, + "baseContracts": [ + { + "baseName": { + "id": 56645, + "name": "ERC20PermitUpgradeable", + "nameLocations": [ + "321:22:112" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 40607, + "src": "321:22:112" + }, + "id": 56646, + "nodeType": "InheritanceSpecifier", + "src": "321:22:112" + }, + { + "baseName": { + "id": 56647, + "name": "AccessControlUpgradeable", + "nameLocations": [ + "345:24:112" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 39385, + "src": "345:24:112" + }, + "id": 56648, + "nodeType": "InheritanceSpecifier", + "src": "345:24:112" + } + ], + "canonicalName": "MOVEToken", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "linearizedBaseContracts": [ + 56719, + 39385, + 41148, + 45166, + 41527, + 40607, + 40764, + 41108, + 42745, + 43725, + 40438, + 42797, + 43689, + 43663, + 40653, + 39639 + ], + "name": "MOVEToken", + "nameLocation": "308:9:112", + "scope": 56720, + "usedErrors": [ + 39402, + 39405, + 40473, + 40480, + 40667, + 41454, + 41457, + 42767, + 42772, + 42777, + 42786, + 42791, + 42796, + 44719, + 44724, + 44729 + ], + "usedEvents": [ + 39410, + 41466, + 41475, + 41484, + 42725, + 43597, + 43606 + ] + } + ], + "license": "MIT" + }, + "id": 112 +} \ No newline at end of file diff --git a/public_key.der b/public_key.der new file mode 100644 index 000000000..a284b32c1 Binary files /dev/null and b/public_key.der differ diff --git a/util/signing/interface/src/cryptography/mod.rs b/util/signing/interface/src/cryptography/mod.rs index edb4aef10..58ee96372 100644 --- a/util/signing/interface/src/cryptography/mod.rs +++ b/util/signing/interface/src/cryptography/mod.rs @@ -14,7 +14,13 @@ macro_rules! fixed_size { impl crate::cryptography::TryFromBytes for $Name { fn try_from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::BYTES_LEN { - Err(anyhow::anyhow!("invalid length"))?; + Err(anyhow::anyhow!( + "invalid length for {}, wants {}, got {}, for {:?}", + stringify!($Name), + Self::BYTES_LEN, + bytes.len(), + bytes + ))?; } let mut inner = [0u8; Self::BYTES_LEN]; @@ -23,6 +29,12 @@ macro_rules! fixed_size { Ok(Self(inner)) } } + + impl crate::cryptography::ToBytes for $Name { + fn to_bytes(&self) -> Vec { + self.0.to_vec() + } + } }; } @@ -33,11 +45,15 @@ pub trait TryFromBytes: Sized { fn try_from_bytes(bytes: &[u8]) -> Result; } +pub trait ToBytes { + fn to_bytes(&self) -> Vec; +} + /// A designator for an elliptic curve. /// /// This trait has no methods, but it binds the types of the public key and /// the signature used by the EC digital signing algorithm. pub trait Curve { - type PublicKey: TryFromBytes; - type Signature; + type PublicKey: TryFromBytes + ToBytes + Send + Sync + std::fmt::Debug; + type Signature: TryFromBytes + ToBytes + Send + Sync + std::fmt::Debug; } diff --git a/util/signing/interface/src/key/mod.rs b/util/signing/interface/src/key/mod.rs new file mode 100644 index 000000000..805b9cd66 --- /dev/null +++ b/util/signing/interface/src/key/mod.rs @@ -0,0 +1,245 @@ +use crate::{cryptography, Signing}; +use std::error; +use std::future::Future; + +pub trait ToCanonicalString { + fn to_canonical_string(&self) -> String; +} + +pub trait TryFromCanonicalString: Sized { + fn try_from_canonical_string(s: &str) -> Result; +} + +#[derive(Debug)] +pub enum Organization { + Movement, + Other(String), +} + +impl ToCanonicalString for Organization { + fn to_canonical_string(&self) -> String { + match self { + Organization::Movement => "movement".to_string(), + Organization::Other(s) => s.clone(), + } + } +} + +impl TryFromCanonicalString for Organization { + fn try_from_canonical_string(s: &str) -> Result { + match s { + "movement" => Ok(Organization::Movement), + _ => Ok(Organization::Other(s.to_string())), + } + } +} + +#[derive(Debug)] +pub enum Environment { + Prod, + Dev, + Staging, +} + +impl ToCanonicalString for Environment { + fn to_canonical_string(&self) -> String { + match self { + Environment::Prod => "prod".to_string(), + Environment::Dev => "devNet".to_string(), + Environment::Staging => "staging".to_string(), + } + } +} + +impl TryFromCanonicalString for Environment { + fn try_from_canonical_string(s: &str) -> Result { + match s { + "prod" => Ok(Environment::Prod), + "devNet" => Ok(Environment::Dev), + "staging" => Ok(Environment::Staging), + _ => Err(format!("invalid environment: {}", s)), + } + } +} + +#[derive(Debug)] +pub enum SoftwareUnit { + FullNode, + Other(String), +} + +impl ToCanonicalString for SoftwareUnit { + fn to_canonical_string(&self) -> String { + match self { + SoftwareUnit::FullNode => "fullNode".to_string(), + SoftwareUnit::Other(s) => s.clone(), + } + } +} + +impl TryFromCanonicalString for SoftwareUnit { + fn try_from_canonical_string(s: &str) -> Result { + match s { + "fullNode" => Ok(SoftwareUnit::FullNode), + _ => Ok(SoftwareUnit::Other(s.to_string())), + } + } +} + +#[derive(Debug)] +pub enum Usage { + McrSettlement, + Other(String), +} + +impl ToCanonicalString for Usage { + fn to_canonical_string(&self) -> String { + match self { + Usage::McrSettlement => "mcr_settlement".to_string(), + Usage::Other(s) => s.clone(), + } + } +} + +impl TryFromCanonicalString for Usage { + fn try_from_canonical_string(s: &str) -> Result { + match s { + "mcr_settlement" => Ok(Usage::McrSettlement), + _ => Ok(Usage::Other(s.to_string())), + } + } +} + +#[derive(Debug)] +pub enum AllowedRoles { + Signer, + Auditor, + Other(String), +} + +impl ToCanonicalString for AllowedRoles { + fn to_canonical_string(&self) -> String { + match self { + AllowedRoles::Signer => "signer".to_string(), + AllowedRoles::Auditor => "auditor".to_string(), + AllowedRoles::Other(s) => s.clone(), + } + } +} + +impl TryFromCanonicalString for AllowedRoles { + fn try_from_canonical_string(s: &str) -> Result { + match s { + "signer" => Ok(AllowedRoles::Signer), + "auditor" => Ok(AllowedRoles::Auditor), + _ => Ok(AllowedRoles::Other(s.to_string())), + } + } +} + +#[derive(Debug)] +pub struct Key { + org: Organization, + environment: Environment, + software_unit: SoftwareUnit, + usage: Usage, + allowed_roles: AllowedRoles, + key_name: String, + app_replica: Option, +} + +impl Key { + pub fn new( + org: Organization, + environment: Environment, + software_unit: SoftwareUnit, + usage: Usage, + allowed_roles: AllowedRoles, + key_name: String, + app_replica: Option, + ) -> Self { + Self { org, environment, software_unit, usage, allowed_roles, key_name, app_replica } + } + + pub fn org(&self) -> &Organization { + &self.org + } + + pub fn environment(&self) -> &Environment { + &self.environment + } + + pub fn software_unit(&self) -> &SoftwareUnit { + &self.software_unit + } + + pub fn usage(&self) -> &Usage { + &self.usage + } + + pub fn allowed_roles(&self) -> &AllowedRoles { + &self.allowed_roles + } + + pub fn key_name(&self) -> &str { + &self.key_name + } + + pub fn app_replica(&self) -> Option<&String> { + self.app_replica.as_ref() + } + + /// Return a delimited canonical string representation of the key. + pub fn to_delimited_canonical_string(&self, delimiter: &str) -> String { + format!( + "{}{delimiter}{}{delimiter}{}{delimiter}{}{delimiter}{}{delimiter}{}{delimiter}{}", + self.org.to_canonical_string(), + self.environment.to_canonical_string(), + self.software_unit.to_canonical_string(), + self.usage.to_canonical_string(), + self.allowed_roles.to_canonical_string(), + self.key_name, + self.app_replica.as_deref().unwrap_or("0"), + delimiter = delimiter + ) + } + + /// Gets a key from a canonical string. + /// Example canonical string: "movement/prod/full_node/mcr_settlement/signer/validator/0" + pub fn try_from_canonical_string(s: &str) -> Result { + let parts: Vec<&str> = s.split('_').collect(); + if parts.len() != 7 { + return Err(format!("invalid key: {}", s)); + } + + Ok(Self { + org: Organization::try_from_canonical_string(parts[0])?, + environment: Environment::try_from_canonical_string(parts[1])?, + software_unit: SoftwareUnit::try_from_canonical_string(parts[2])?, + usage: Usage::try_from_canonical_string(parts[3])?, + allowed_roles: AllowedRoles::try_from_canonical_string(parts[4])?, + key_name: parts[5].to_string(), + app_replica: Some(parts[6].to_string()), + }) + } + + /// Gets a key from a canonical string environment variable + pub fn try_from_env_var(var: &str) -> Result { + let s = std::env::var(var).map_err(|e| format!("{}: {}", var, e))?; + Self::try_from_canonical_string(&s) + } +} + +/// Errors thrown by [SignerBuilder]. +#[derive(Debug, thiserror::Error)] +pub enum SignerBuilderError { + #[error("building signer failed")] + BuildingSigner(#[source] Box), + #[error("internal error: {0}")] + Internal(String), +} + +pub trait SignerBuilder> { + /// Get async signer for a key. + fn build(&self, key: Key) -> impl Future> + Send; +} diff --git a/util/signing/interface/src/lib.rs b/util/signing/interface/src/lib.rs index 646573996..bc12b6edb 100644 --- a/util/signing/interface/src/lib.rs +++ b/util/signing/interface/src/lib.rs @@ -3,7 +3,7 @@ use std::future::Future; use std::marker::PhantomData; pub mod cryptography; -pub mod manager; +pub mod key; /// Errors thrown by Signer #[derive(Debug, thiserror::Error)] @@ -43,10 +43,13 @@ pub struct Signer { _phantom_curve: PhantomData, } -impl Signer { +impl Signer +where + O: Signing, + C: cryptography::Curve, +{ /// Binds the signing provider with the specific curve selection. - pub fn new(provider: O, curve: C) -> Self { - let _ = curve; + pub fn new(provider: O) -> Self { Self { provider, _phantom_curve: PhantomData } } diff --git a/util/signing/interface/src/manager/mod.rs b/util/signing/interface/src/manager/mod.rs deleted file mode 100644 index f978b9e92..000000000 --- a/util/signing/interface/src/manager/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::{cryptography, Signing}; -use std::error; - -/// Errors thrown by [KeyManager]. -#[derive(Debug, thiserror::Error)] -pub enum KeyManagerError { - #[error("building signer failed")] - BuildingSigner(#[source] Box), -} - -pub trait KeyManager> { - /// A key manager is bound by a specific identifier type. - /// the Curve (C) and the Signing (S) types are generic because it is presumed the key manager can handle multiple (generic) curves and signing services, but potentially only one key identifier type. - type Id; - - /// Get async signer for a key. - fn build_signer(&self, key_id: Self::Id) -> Result; -} diff --git a/util/signing/providers/aws-kms/Cargo.toml b/util/signing/providers/aws-kms/Cargo.toml index 018066fdc..0d6b57e4a 100644 --- a/util/signing/providers/aws-kms/Cargo.toml +++ b/util/signing/providers/aws-kms/Cargo.toml @@ -10,8 +10,13 @@ publish = { workspace = true } rust-version = { workspace = true } [dependencies] -movement-signer = { workspace = true } +anyhow = { workspace = true } aws-sdk-kms = { workspace = true } +aws-types = { workspace = true } +aws-config = { workspace = true } +movement-signer = { workspace = true } +secp256k1 = "0.24" +simple_asn1 = "0.6" [lints] workspace = true diff --git a/util/signing/providers/aws-kms/src/cryptography/mod.rs b/util/signing/providers/aws-kms/src/cryptography/mod.rs index 3e5840107..8f5b64818 100644 --- a/util/signing/providers/aws-kms/src/cryptography/mod.rs +++ b/util/signing/providers/aws-kms/src/cryptography/mod.rs @@ -1 +1,14 @@ pub mod secp256k1; +use aws_sdk_kms::types::{KeySpec, KeyUsageType, SigningAlgorithmSpec}; + +/// Defines the needed methods for providing a definition of cryptography used with AWS KMS +pub trait AwsKmsCryptographySpec { + /// Returns the [KeySpec] for the desired cryptography + fn key_spec() -> KeySpec; + + /// Returns the [KeyUsageType] for the desired cryptography + fn key_usage_type() -> KeyUsageType; + + /// Returns the [SigningAlgorithmSpec] for the desired cryptography + fn signing_algorithm_spec() -> SigningAlgorithmSpec; +} diff --git a/util/signing/providers/aws-kms/src/cryptography/secp256k1/mod.rs b/util/signing/providers/aws-kms/src/cryptography/secp256k1/mod.rs index 481d4e40e..7297885bf 100644 --- a/util/signing/providers/aws-kms/src/cryptography/secp256k1/mod.rs +++ b/util/signing/providers/aws-kms/src/cryptography/secp256k1/mod.rs @@ -1,19 +1,8 @@ +use crate::cryptography::AwsKmsCryptographySpec; use aws_sdk_kms::types::{KeySpec, KeyUsageType, SigningAlgorithmSpec}; use movement_signer::cryptography::secp256k1::Secp256k1; -/// Defines the needed methods for providing a definition of cryptography used with AWS KMS -pub trait AwsKmsCryptography { - /// Returns the [KeySpec] for the desired cryptography - fn key_spec() -> KeySpec; - - /// Returns the [KeyUsageType] for the desired cryptography - fn key_usage_type() -> KeyUsageType; - - /// Returns the [SigningAlgorithmSpec] for the desired cryptography - fn signing_algorithm_spec() -> SigningAlgorithmSpec; -} - -impl AwsKmsCryptography for Secp256k1 { +impl AwsKmsCryptographySpec for Secp256k1 { fn key_spec() -> KeySpec { KeySpec::EccSecgP256K1 } diff --git a/util/signing/providers/aws-kms/src/hsm/key.rs b/util/signing/providers/aws-kms/src/hsm/key.rs new file mode 100644 index 000000000..2db4e1217 --- /dev/null +++ b/util/signing/providers/aws-kms/src/hsm/key.rs @@ -0,0 +1,43 @@ +use crate::{cryptography::AwsKmsCryptographySpec, hsm::AwsKms}; +use movement_signer::{ + cryptography::Curve, + key::{Key, SignerBuilder, SignerBuilderError}, +}; + +pub struct Builder { + create_key: bool, + _cryptography_marker: std::marker::PhantomData, +} + +impl Builder +where + C: Curve, +{ + pub fn new() -> Self { + Self { create_key: false, _cryptography_marker: std::marker::PhantomData } + } + + pub fn create_key(mut self, create_key: bool) -> Self { + self.create_key = create_key; + self + } +} + +impl SignerBuilder> for Builder +where + C: Curve + AwsKmsCryptographySpec + Send + Sync, +{ + async fn build(&self, key: Key) -> Result, SignerBuilderError> { + let mut hsm = AwsKms::try_from_env() + .await + .map_err(|e| SignerBuilderError::Internal(e.to_string()))?; + hsm.set_key_id(key.to_delimited_canonical_string("/")); + if self.create_key { + hsm = hsm + .create_key() + .await + .map_err(|e| SignerBuilderError::Internal(e.to_string()))?; + } + Ok(hsm) + } +} diff --git a/util/signing/providers/aws-kms/src/hsm/mod.rs b/util/signing/providers/aws-kms/src/hsm/mod.rs new file mode 100644 index 000000000..89b4881d9 --- /dev/null +++ b/util/signing/providers/aws-kms/src/hsm/mod.rs @@ -0,0 +1,269 @@ +use crate::cryptography::AwsKmsCryptographySpec; +use anyhow::Context; +use aws_sdk_kms::error::ProvideErrorMetadata; +use aws_sdk_kms::operation::RequestId; +use aws_sdk_kms::primitives::Blob; +use aws_sdk_kms::Client; +use movement_signer::cryptography::TryFromBytes; +use movement_signer::{cryptography::Curve, SignerError, Signing}; +use secp256k1::ecdsa::Signature as Secp256k1Signature; +pub mod key; +use simple_asn1::{ASN1Block, from_der}; + +/// An AWS KMS HSM. +pub struct AwsKms { + client: Client, + key_id: String, + _cryptography_marker: std::marker::PhantomData, +} + +impl AwsKms +where + C: Curve + AwsKmsCryptographySpec, +{ + /// Creates a new AWS KMS HSM + pub fn new(client: Client, key_id: String) -> Self { + Self { client, key_id, _cryptography_marker: std::marker::PhantomData } + } + + /// Sets the key id + pub fn set_key_id(&mut self, key_id: String) { + self.key_id = key_id; + } + + /// Tries to create a new AWS KMS HSM from the environment + pub async fn try_from_env() -> Result { + let key_id = std::env::var("AWS_KMS_KEY_ID").unwrap_or("0x1".to_string()); + let config = aws_config::load_from_env().await; + let client = aws_sdk_kms::Client::new(&config); + + Ok(Self::new(client, key_id)) + } + + /// Creates in AWS KMS matching the provided key id. + pub async fn create_key(self) -> Result { + let res = self + .client + .create_key() + .key_spec(C::key_spec()) + .key_usage(C::key_usage_type()) + .send() + .await?; + + let key_id = res.key_metadata().context("No key metadata available")?.key_id().to_string(); + + Ok(Self::new(self.client, key_id)) + } + + pub async fn resolve_key_id(&self) -> Result { + let alias_name = format!("alias/{}", self.key_id); // Ensure the alias format is correct + + let key_metadata = self + .client + .describe_key() + .key_id(&alias_name) + .send() + .await + .map_err(|e| { + println!("Error resolving key ID from alias: {:?}", e); + SignerError::Internal(format!( + "Failed to resolve key ID: {:?}", + e + )) + })?; + + let key_id = key_metadata + .key_metadata() + .and_then(|metadata| Some(metadata.key_id())) + .map(|key_id| key_id.to_string()) + .ok_or_else(|| { + SignerError::Internal("Failed to retrieve key ID".to_string()) + })?; + + Ok(key_id) + } +} + +impl Signing for AwsKms +where + C: Curve + AwsKmsCryptographySpec + Sync, +{ + async fn sign(&self, message: &[u8]) -> Result { + println!("Preparing to sign message. Message bytes: {:?}", message); + + // Ensure the alias has the correct prefix + let key_alias = format!("alias/{}", self.key_id); + println!("Using Key Alias: {}", key_alias); + + // Convert the message into a Blob + let blob = Blob::new(message); + + // Use the `sign` API with the alias directly + let res = self + .client + .sign() + .key_id(&key_alias) + .signing_algorithm(C::signing_algorithm_spec()) + .message(blob) + .send() + .await + .map_err(|e| { + // Log detailed error information + if let Some(service_error) = e.as_service_error() { + let code = service_error.code().unwrap_or("Unknown").to_string(); + let message = + service_error.message().unwrap_or("No message provided").to_string(); + let request_id = service_error + .request_id() + .map(|id| id.to_string()) + .unwrap_or_else(|| "No Request ID".to_string()); + + println!( + "AWS Service Error: Code: {}, Message: {}, Request ID: {}", + code, message, request_id + ); + } else { + // Non-service error handling + println!("Non-service error occurred: {:?}", e); + } + + // Return a formatted error + SignerError::Internal(format!("Failed to sign: {:?}", e)) + })?; + + println!("Response signature (DER format): {:?}", res.signature()); + + // Extract the DER-encoded signature + let der_signature = res + .signature() + .context("No signature available") + .map_err(|e| SignerError::Internal(e.to_string()))?; + + // Convert DER signature to raw format using secp256k1 + let secp_signature = Secp256k1Signature::from_der(der_signature.as_ref()) + .map_err(|e| SignerError::Internal(format!("Failed to parse DER signature: {}", e)))?; + + let raw_signature = secp_signature.serialize_compact(); + println!("Raw signature: {:?}", raw_signature); + + // Convert the raw signature into the appropriate curve type + let signature = ::Signature::try_from_bytes(&raw_signature).map_err(|e| { + SignerError::Internal(format!("Failed to convert signature: {}", e.to_string())) + })?; + + Ok(signature) + } + + async fn public_key(&self) -> Result { + // Resolve the Key ID + let key_id = self.resolve_key_id().await.map_err(|e| { + println!("Error resolving key ID: {:?}", e); + SignerError::Internal(format!("Failed to resolve key ID: {:?}", e)) + })?; + + // Fetch the public key from AWS KMS + let res = self + .client + .get_public_key() + .key_id(&key_id) // Use the resolved Key ID + .send() + .await + .map_err(|e| { + println!("Error calling get_public_key: {:?}", e); + SignerError::Internal(format!("Failed to get public key: {:?}", e)) + })?; + + println!("get_public_key response: {:?}", res); + + // Extract the DER-encoded public key + let public_key_der = res + .public_key() + .context("No public key available") + .map_err(|e| { + println!("Error extracting public key: {:?}", e); + SignerError::Internal(e.to_string()) + })?; + + // Convert the DER-encoded public key to raw format + let raw_public_key = extract_raw_public_key(public_key_der.as_ref()).map_err(|e| { + println!("Error decoding DER-encoded public key: {:?}", e); + SignerError::Internal(e.to_string()) + })?; + + // Convert raw public key to the required curve-specific format + let public_key = C::PublicKey::try_from_bytes(&raw_public_key).map_err(|e| { + println!("Error converting public key bytes: {:?}", e); + SignerError::Internal(e.to_string()) + })?; + + Ok(public_key) + } + + +} + +// Utility function for DER-to-raw signature conversion +pub fn der_to_raw_signature(der: &[u8]) -> Result<[u8; 64], String> { + if der.len() < 8 || der[0] != 0x30 { + return Err("Invalid DER signature".to_string()); + } + + let r_len = der[3] as usize; + let r_start = 4; + let r_end = r_start + r_len; + + let s_len = der[r_end + 1] as usize; + let s_start = r_end + 2; + let s_end = s_start + s_len; + + if r_end > der.len() || s_end > der.len() { + return Err("Invalid DER signature length".to_string()); + } + + // Extract `r` and `s` + let r = &der[r_start..r_end]; + let s = &der[s_start..s_end]; + + // Ensure `r` and `s` are 32 bytes by trimming leading zeros + let mut raw_r = [0u8; 32]; + let mut raw_s = [0u8; 32]; + + if r.len() > 32 { + return Err("Invalid r length".to_string()); + } + if s.len() > 32 { + return Err("Invalid s length".to_string()); + } + + raw_r[32 - r.len()..].copy_from_slice(r); + raw_s[32 - s.len()..].copy_from_slice(s); + + // Combine `r` and `s` into a 64-byte raw signature + let mut raw_signature = [0u8; 64]; + raw_signature[..32].copy_from_slice(&raw_r); + raw_signature[32..].copy_from_slice(&raw_s); + + Ok(raw_signature) +} + +fn extract_raw_public_key(der: &[u8]) -> Result, anyhow::Error> { + let asn1_blocks = from_der(der).context("Failed to parse DER-encoded public key")?; + + if let Some(ASN1Block::Sequence(_, blocks)) = asn1_blocks.get(0) { + if let Some(ASN1Block::BitString(_, _, key_bytes)) = blocks.get(1) { + // Ensure the key is in uncompressed format and strip the prefix + if key_bytes.len() == 65 && key_bytes[0] == 4 { + return Ok(key_bytes[1..33].to_vec()); // Return the X coordinate only + } else { + return Err(anyhow::anyhow!( + "Unexpected public key format or length: {:?}", + key_bytes + )); + } + } + } + + Err(anyhow::anyhow!("Failed to extract raw public key from DER")) +} + + diff --git a/util/signing/providers/aws-kms/src/lib.rs b/util/signing/providers/aws-kms/src/lib.rs index 18f57b93b..63d77a7f1 100644 --- a/util/signing/providers/aws-kms/src/lib.rs +++ b/util/signing/providers/aws-kms/src/lib.rs @@ -1 +1,2 @@ pub mod cryptography; +pub mod hsm; diff --git a/util/signing/providers/hashicorp-vault/src/cryptography/ed25519/mod.rs b/util/signing/providers/hashicorp-vault/src/cryptography/ed25519/mod.rs index 96958ff25..13a4612ff 100644 --- a/util/signing/providers/hashicorp-vault/src/cryptography/ed25519/mod.rs +++ b/util/signing/providers/hashicorp-vault/src/cryptography/ed25519/mod.rs @@ -1,8 +1,8 @@ -use crate::cryptography::HashiCorpVaultCryptography; +use crate::cryptography::HashiCorpVaultCryptographySpec; use movement_signer::cryptography::ed25519::Ed25519; use vaultrs::api::transit::KeyType; -impl HashiCorpVaultCryptography for Ed25519 { +impl HashiCorpVaultCryptographySpec for Ed25519 { fn key_type() -> KeyType { KeyType::Ed25519 } diff --git a/util/signing/providers/hashicorp-vault/src/cryptography/mod.rs b/util/signing/providers/hashicorp-vault/src/cryptography/mod.rs index 88e8ee7bd..a0adcb479 100644 --- a/util/signing/providers/hashicorp-vault/src/cryptography/mod.rs +++ b/util/signing/providers/hashicorp-vault/src/cryptography/mod.rs @@ -2,7 +2,7 @@ pub mod ed25519; use vaultrs::api::transit::KeyType; /// Defines the needed methods for providing a definition of cryptography used with HashiCorp Vault -pub trait HashiCorpVaultCryptography { +pub trait HashiCorpVaultCryptographySpec { /// Returns the [KeyType] for the desired cryptography fn key_type() -> KeyType; } diff --git a/util/signing/providers/hashicorp-vault/src/hsm/key.rs b/util/signing/providers/hashicorp-vault/src/hsm/key.rs new file mode 100644 index 000000000..0b640b8d9 --- /dev/null +++ b/util/signing/providers/hashicorp-vault/src/hsm/key.rs @@ -0,0 +1,42 @@ +use crate::{cryptography::HashiCorpVaultCryptographySpec, hsm::HashiCorpVault}; +use movement_signer::{ + cryptography::Curve, + key::{Key, SignerBuilder, SignerBuilderError}, +}; + +pub struct Builder { + create_key: bool, + _cryptography_marker: std::marker::PhantomData, +} + +impl Builder +where + C: Curve, +{ + pub fn new() -> Self { + Self { create_key: false, _cryptography_marker: std::marker::PhantomData } + } + + pub fn create_key(mut self, create_key: bool) -> Self { + self.create_key = create_key; + self + } +} + +impl SignerBuilder> for Builder +where + C: Curve + HashiCorpVaultCryptographySpec + Send + Sync, +{ + async fn build(&self, key: Key) -> Result, SignerBuilderError> { + let mut hsm = HashiCorpVault::try_from_env() + .map_err(|e| SignerBuilderError::Internal(e.to_string()))?; + hsm.set_key_id(key.to_delimited_canonical_string("_")); + if self.create_key { + hsm = hsm + .create_key() + .await + .map_err(|e| SignerBuilderError::Internal(e.to_string()))?; + } + Ok(hsm) + } +} diff --git a/util/signing/providers/hashicorp-vault/src/hsm/mod.rs b/util/signing/providers/hashicorp-vault/src/hsm/mod.rs index 17b4a1228..051a33ff4 100644 --- a/util/signing/providers/hashicorp-vault/src/hsm/mod.rs +++ b/util/signing/providers/hashicorp-vault/src/hsm/mod.rs @@ -1,46 +1,39 @@ -use crate::cryptography::HashiCorpVaultCryptography; +pub mod key; + +use crate::cryptography::HashiCorpVaultCryptographySpec; use anyhow::Context; use movement_signer::cryptography::TryFromBytes; -use movement_signer::{ - cryptography::{ed25519::Ed25519, Curve}, - SignerError, Signing, -}; +use movement_signer::{cryptography::Curve, SignerError, Signing}; use vaultrs::api::transit::{requests::CreateKeyRequest, responses::ReadKeyData}; use vaultrs::client::{VaultClient, VaultClientSettingsBuilder}; -use vaultrs::transit::key; +use vaultrs::transit::data; +use vaultrs::transit::key as transit_key; /// A HashiCorp Vault HSM. -pub struct HashiCorpVault { +pub struct HashiCorpVault { client: VaultClient, key_name: String, mount_name: String, - pub public_key: ::PublicKey, _cryptography_marker: std::marker::PhantomData, } impl HashiCorpVault where - C: Curve + HashiCorpVaultCryptography, + C: Curve + HashiCorpVaultCryptographySpec, { /// Creates a new HashiCorp Vault HSM - pub fn new( - client: VaultClient, - key_name: String, - mount_name: String, - public_key: C::PublicKey, - ) -> Self { - Self { - client, - key_name, - mount_name, - public_key, - _cryptography_marker: std::marker::PhantomData, - } + pub fn new(client: VaultClient, key_name: String, mount_name: String) -> Self { + Self { client, key_name, mount_name, _cryptography_marker: std::marker::PhantomData } + } + + /// Sets the key id + pub fn set_key_id(&mut self, key_id: String) { + self.key_name = key_id; } /// Tries to create a new HashiCorp Vault HSM from the environment pub fn try_from_env() -> Result { - let address = std::env::var("VAULT_ADDRESS").context("VAULT_ADDRESS not set")?; + let address = std::env::var("VAULT_ADDR").context("VAULT_ADDR not set")?; let token = std::env::var("VAULT_TOKEN").context("VAULT_TOKEN not set")?; let namespace = std::env::var("VAULT_NAMESPACE").unwrap_or_else(|_| "admin".to_string()); let client = VaultClient::new( @@ -51,88 +44,141 @@ where .build()?, )?; - let key_name = std::env::var("VAULT_KEY_NAME").context("VAULT_KEY_NAME not set")?; + let key_name = std::env::var("VAULT_KEY_NAME") + .context("VAULT_KEY_NAME not set")?; let mount_name = std::env::var("VAULT_MOUNT_NAME").context("VAULT_MOUNT_NAME not set")?; - let public_key = std::env::var("VAULT_PUBLIC_KEY").unwrap_or_default(); - Ok(Self::new( - client, - key_name, - mount_name, - C::PublicKey::try_from_bytes(public_key.as_bytes())?, - )) + Ok(Self::new(client, key_name, mount_name)) } /// Creates a new key in the transit backend pub async fn create_key(self) -> Result { - key::create( + transit_key::create( &self.client, self.mount_name.as_str(), self.key_name.as_str(), Some(CreateKeyRequest::builder().key_type(C::key_type()).derived(false)), ) .await - .context("Failed to create key")?; + .map_err(|e| anyhow::anyhow!(e))?; Ok(self) } - - /// Fills with a public key fetched from vault. - pub async fn fill_with_public_key(self) -> Result { - let res = key::read(&self.client, self.mount_name.as_str(), self.key_name.as_str()) - .await - .context("Failed to read key")?; - println!("Read key: {:?}", res); - - let public_key = match res.keys { - ReadKeyData::Symmetric(_) => { - return Err(anyhow::anyhow!("Symmetric keys are not supported")); - } - ReadKeyData::Asymmetric(keys) => { - let key = keys.values().next().context("No key found")?; - base64::decode(key.public_key.as_str()).context("Failed to decode public key")? - } - }; - - println!("Public key: {:?}", public_key); - Ok(Self::new( - self.client, - self.key_name, - self.mount_name, - C::PublicKey::try_from_bytes(public_key.as_slice())?, - )) - } } -impl Signing for HashiCorpVault { - async fn sign(&self, _message: &[u8]) -> Result<::Signature, SignerError> { - unimplemented!() - } +impl Signing for HashiCorpVault +where + C: Curve + HashiCorpVaultCryptographySpec + Sync, +{ + async fn sign(&self, message: &[u8]) -> Result { + println!("Key name: {:?}", self.key_name.as_str()); + + let res = data::sign( + &self.client, + self.mount_name.as_str(), + self.key_name.replace("/", "_").as_str(), + base64::encode(message).as_str(), + None, + ) + .await + .map_err(|e| { + let error_msg = format!("Failed to sign message: {:?}", e); + println!("{}", error_msg); + SignerError::Internal(error_msg) + })?; + + // Log the full response + println!("Signature response: {:?}", res); + + if !res.signature.starts_with("vault") { + return Err(SignerError::Internal("Invalid signature format".to_string())); + } + + // Extract the key version from the signature + let version_end_index = res.signature[6..] + .find(':') + .ok_or_else(|| SignerError::Internal("Invalid signature format".to_string()))? + + 6; - async fn public_key(&self) -> Result<::PublicKey, SignerError> { - let res = key::read(&self.client, self.mount_name.as_str(), self.key_name.as_str()) - .await - .context("Failed to read key") + // Determine split index dynamically + let split_index = version_end_index + 1; + + // Split and decode the signature + let signature_str = &res.signature[split_index..]; + + let signature = base64::decode(signature_str) + .context("Failed to decode base64 signature from Vault") .map_err(|e| SignerError::Internal(e.to_string()))?; - println!("Read key: {:?}", res); - + + if signature.len() != 64 { + return Err(SignerError::Internal(format!( + "Unexpected signature length: {} bytes", + signature.len() + ))); + } + + let parsed_signature = C::Signature::try_from_bytes(&signature).map_err(|e| { + SignerError::Internal(format!( + "Failed to parse signature into expected format: {:?}", + e + )) + })?; + + Ok(parsed_signature) + } + + async fn public_key(&self) -> Result { + println!("Attempting to read Vault key: {}", self.key_name); + + // Read the key from Vault + let res = transit_key::read( + &self.client, + self.mount_name.as_str(), + self.key_name.replace("/", "_").as_str(), + ) + .await + .map_err(|e| { + println!( + "Error reading key '{}' from mount '{}': {:?}", + self.key_name, self.mount_name, e + ); + SignerError::Internal(format!("Failed to read key '{}': {:?}", self.key_name, e)) + })?; + + println!("Key read successfully: {:?}", res); + + // Match the key type and determine the latest version let public_key = match res.keys { ReadKeyData::Symmetric(_) => { - return Err(SignerError::Internal("Symmetric keys are not supported".to_string())); + println!("Key '{}' is symmetric and not supported", self.key_name); + return Err(SignerError::Internal( + "Symmetric keys are not supported".to_string(), + )); } ReadKeyData::Asymmetric(keys) => { - let key = keys - .values() - .next() - .context("No key found") - .map_err(|e| SignerError::KeyNotFound)?; - base64::decode(key.public_key.as_str()) - .context("Failed to decode public key") - .map_err(|e| SignerError::Internal(e.to_string()))? + // Use the number of items in the map as the version + let latest_version = keys.len().to_string(); + + let key = keys.get(&latest_version).context("Key version not found").map_err(|e| { + println!("Key version '{}' not found: {:?}", latest_version, e); + SignerError::KeyNotFound + })?; + + base64::decode(&key.public_key).map_err(|e| { + println!("Failed to decode public key: {:?}", e); + SignerError::Internal(e.to_string()) + })? } }; - - Ok(::PublicKey::try_from_bytes(public_key.as_slice()) - .map_err(|e| SignerError::Internal(e.to_string()))?) + + Ok(C::PublicKey::try_from_bytes(&public_key).map_err(|e| { + println!( + "Error converting public key to curve type: {:?}. Bytes: {:?}", + e, public_key + ); + SignerError::Internal(e.to_string()) + })?) } + + } diff --git a/util/signing/signing-admin/Cargo.toml b/util/signing/signing-admin/Cargo.toml new file mode 100644 index 000000000..2fc23ff5d --- /dev/null +++ b/util/signing/signing-admin/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "signing_admin" +version = "0.1.0" +edition = "2021" +authors = ["Your Name "] +description = "CLI for managing signing keys" +license = "MIT" +repository = "https://github.com/your/repo" + +[dependencies] +anyhow = "1.0" +async-trait = { workspace = true } +aws-config = { workspace = true } +aws-sdk-kms = { workspace = true } +base64 = { workspace = true } +clap = { version = "4.0", features = ["derive"] } +movement-signer = { workspace = true } +movement-signer-aws-kms = { workspace = true } +movement-signer-hashicorp-vault = { workspace = true } +reqwest = { version = "0.11", features = ["json"] } +serde_json = { workspace = true } +simple_asn1 = "0.6" +tokio = { version = "1", features = ["full"] } +uuid = { workspace = true } +vaultrs = { workspace = true } + +[[bin]] +name = "signing-admin" +path = "src/main.rs" diff --git a/util/signing/signing-admin/src/application/mod.rs b/util/signing/signing-admin/src/application/mod.rs new file mode 100644 index 000000000..eb50b543b --- /dev/null +++ b/util/signing/signing-admin/src/application/mod.rs @@ -0,0 +1,42 @@ +use anyhow::Result; + +#[async_trait::async_trait] +pub trait Application { + async fn notify_public_key(&self, public_key: Vec) -> Result<()>; +} + +pub struct HttpApplication { + app_url: String, +} + +impl HttpApplication { + pub fn new(app_url: String) -> Self { + Self { app_url } + } +} + +#[async_trait::async_trait] +impl Application for HttpApplication { + async fn notify_public_key(&self, public_key: Vec) -> Result<()> { + let endpoint = format!("{}/public_key/set", self.app_url); + println!("Notifying application at {} with public key {:?}", endpoint, public_key); + + let client = reqwest::Client::new(); + let response = client + .post(&endpoint) + .json(&serde_json::json!({ "public_key": public_key })) + .send() + .await?; + + if !response.status().is_success() { + anyhow::bail!( + "Failed to notify application. Status: {}, Body: {:?}", + response.status(), + response.text().await? + ); + } + + println!("Successfully notified the application."); + Ok(()) + } +} diff --git a/util/signing/signing-admin/src/backend/aws.rs b/util/signing/signing-admin/src/backend/aws.rs new file mode 100644 index 000000000..18dbb82ca --- /dev/null +++ b/util/signing/signing-admin/src/backend/aws.rs @@ -0,0 +1,66 @@ +use anyhow::{Context, Result}; +use aws_config; +use aws_sdk_kms::{Client as KmsClient}; +use aws_sdk_kms::types::Tag; +use super::SigningBackend; + +pub struct AwsBackend; + +impl AwsBackend { + pub fn new() -> Self { + Self {} + } + + async fn create_client() -> Result { + let aws_config = aws_config::load_from_env().await; + Ok(KmsClient::new(&aws_config)) + } + + async fn create_key(client: &KmsClient) -> Result { + let response = client + .create_key() + .description("Key for signing and verification") + .key_usage(aws_sdk_kms::types::KeyUsageType::SignVerify) + .customer_master_key_spec(aws_sdk_kms::types::CustomerMasterKeySpec::EccSecgP256K1) + .tags( + Tag::builder() + .tag_key("unique_id") + .tag_value("tag") + .build() + .context("Failed to build AWS KMS tag")?, + ) + .send() + .await + .context("Failed to create key with AWS KMS")?; + + response + .key_metadata() + .and_then(|meta| Some(meta.key_id().to_string())) + .context("Failed to retrieve key ID from AWS response") + } +} + +#[async_trait::async_trait] +impl SigningBackend for AwsBackend { + async fn rotate_key(&self, key_id: &str) -> Result<()> { + let client = Self::create_client().await?; + + // Ensure the key_id starts with "alias/" + let full_alias = if key_id.starts_with("alias/") { + key_id.to_string() + } else { + format!("alias/{}", key_id) + }; + + let new_key_id = Self::create_key(&client).await?; + client + .update_alias() + .alias_name(&full_alias) + .target_key_id(&new_key_id) + .send() + .await + .context("Failed to update AWS KMS alias")?; + + Ok(()) + } +} diff --git a/util/signing/signing-admin/src/backend/mod.rs b/util/signing/signing-admin/src/backend/mod.rs new file mode 100644 index 000000000..8a2ca7829 --- /dev/null +++ b/util/signing/signing-admin/src/backend/mod.rs @@ -0,0 +1,30 @@ +pub mod aws; +pub mod vault; + +use anyhow::Result; +use async_trait::async_trait; +use aws::AwsBackend; +use vault::VaultBackend; + +/// The trait that all signing backends must implement. +#[async_trait] +pub trait SigningBackend { + async fn rotate_key(&self, key_id: &str) -> Result<()>; +} + +/// Enum to represent the different backends. +pub enum Backend { + Aws(AwsBackend), + Vault(VaultBackend), +} + +/// Implement the SigningBackend trait for the Backend enum. +#[async_trait] +impl SigningBackend for Backend { + async fn rotate_key(&self, key_id: &str) -> Result<()> { + match self { + Backend::Aws(aws) => aws.rotate_key(key_id).await, + Backend::Vault(vault) => vault.rotate_key(key_id).await, + } + } +} diff --git a/util/signing/signing-admin/src/backend/vault.rs b/util/signing/signing-admin/src/backend/vault.rs new file mode 100644 index 000000000..db958e8cb --- /dev/null +++ b/util/signing/signing-admin/src/backend/vault.rs @@ -0,0 +1,32 @@ +use anyhow::{Context, Result}; +use vaultrs::client::{VaultClient, VaultClientSettingsBuilder}; +use vaultrs::transit::key::rotate; +use super::SigningBackend; + +pub struct VaultBackend; + +impl VaultBackend { + pub fn new() -> Self { + Self {} + } + + async fn create_client(vault_url: &str, token: &str) -> Result { + let settings = VaultClientSettingsBuilder::default() + .address(vault_url) + .token(token) + .namespace(Some("admin".to_string())) + .build() + .context("Failed to build Vault client settings")?; + VaultClient::new(settings).context("Failed to create Vault client") + } +} + +#[async_trait::async_trait] +impl SigningBackend for VaultBackend { + async fn rotate_key(&self, key_id: &str) -> Result<()> { + let vault_url = std::env::var("VAULT_URL").context("Missing VAULT_URL environment variable")?; + let token = std::env::var("VAULT_TOKEN").context("Missing VAULT_TOKEN environment variable")?; + let client = Self::create_client(&vault_url, &token).await?; + rotate(&client, "transit", key_id).await.context("Failed to rotate key in Vault") + } +} diff --git a/util/signing/signing-admin/src/cli/mod.rs b/util/signing/signing-admin/src/cli/mod.rs new file mode 100644 index 000000000..48ea8f79c --- /dev/null +++ b/util/signing/signing-admin/src/cli/mod.rs @@ -0,0 +1,24 @@ +use clap::{Parser, Subcommand}; + +pub mod rotate_key; + +#[derive(Parser, Debug)] +#[clap(name = "signing-admin", about = "CLI for managing signing keys")] +pub struct CLI { + #[clap(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + RotateKey { + #[clap(long, help = "Canonical string of the key (alias for the backend key)")] + canonical_string: String, + + #[clap(long, help = "Application URL to notify about the key rotation")] + application_url: String, + + #[clap(long, help = "Backend to use (e.g., 'vault', 'aws')")] + backend: String, + }, +} diff --git a/util/signing/signing-admin/src/cli/rotate_key.rs b/util/signing/signing-admin/src/cli/rotate_key.rs new file mode 100644 index 000000000..9122db095 --- /dev/null +++ b/util/signing/signing-admin/src/cli/rotate_key.rs @@ -0,0 +1,102 @@ +use anyhow::{Context, Result}; +use movement_signer::{ + cryptography::{ed25519::Ed25519, secp256k1::Secp256k1}, + Signing, +}; +use movement_signer_aws_kms::hsm::AwsKms; +use movement_signer_hashicorp_vault::hsm::HashiCorpVault; +use signing_admin::{ + application::{Application, HttpApplication}, + backend::{aws::AwsBackend, vault::VaultBackend, Backend}, + key_manager::KeyManager, +}; +use vaultrs::client::{VaultClient, VaultClientSettingsBuilder}; + +/// Enum to encapsulate different signers +enum SignerBackend { + Vault(HashiCorpVault), + Aws(AwsKms), +} + +impl SignerBackend { + /// Retrieve the public key from the signer + async fn public_key(&self) -> Result> { + match self { + SignerBackend::Vault(signer) => { + let public_key = signer.public_key().await?; + Ok(public_key.as_bytes().to_vec()) + } + SignerBackend::Aws(signer) => { + let public_key = signer.public_key().await?; + Ok(public_key.as_bytes().to_vec()) + } + } + } +} + +pub async fn rotate_key( + canonical_string: String, + application_url: String, + backend_name: String, +) -> Result<()> { + let application = HttpApplication::new(application_url); + + let backend = match backend_name.as_str() { + "vault" => Backend::Vault(VaultBackend::new()), + "aws" => Backend::Aws(AwsBackend::new()), + _ => return Err(anyhow::anyhow!("Unsupported backend: {}", backend_name)), + }; + + let signer = match backend_name.as_str() { + "vault" => { + let vault_url = + std::env::var("VAULT_ADDR").context("Missing VAULT_ADDR environment variable")?; + let vault_token = + std::env::var("VAULT_TOKEN").context("Missing VAULT_TOKEN environment variable")?; + + let client = VaultClient::new( + VaultClientSettingsBuilder::default() + .address(vault_url) + .token(vault_token) + .namespace(Some("admin".to_string())) + .build() + .context("Failed to build Vault client settings")?, + ) + .context("Failed to create Vault client")?; + + SignerBackend::Vault(HashiCorpVault::::new( + client, + canonical_string.clone(), + "transit".to_string(), + )) + } + "aws" => { + let aws_config = aws_config::load_from_env().await; + let client = aws_sdk_kms::Client::new(&aws_config); + + SignerBackend::Aws(AwsKms::::new(client, canonical_string.clone())) + } + _ => return Err(anyhow::anyhow!("Unsupported signer backend: {}", backend_name)), + }; + + let key_manager = KeyManager::new(application, backend); + + key_manager + .rotate_key(&canonical_string) + .await + .context("Failed to rotate the key")?; + + let public_key = signer + .public_key() + .await + .context("Failed to fetch the public key from signer")?; + + key_manager + .application + .notify_public_key(public_key) + .await + .context("Failed to notify the application with the public key")?; + + println!("Key rotation and notification completed successfully."); + Ok(()) +} diff --git a/util/signing/signing-admin/src/key_manager.rs b/util/signing/signing-admin/src/key_manager.rs new file mode 100644 index 000000000..ad259f12e --- /dev/null +++ b/util/signing/signing-admin/src/key_manager.rs @@ -0,0 +1,24 @@ +use anyhow::Result; +use movement_signer::Signing; +use super::application::Application; +use super::backend::SigningBackend; + +pub struct KeyManager { + pub application: A, + pub backend: B, +} + +impl KeyManager +where + A: Application, + B: SigningBackend, +{ + pub fn new(application: A, backend: B) -> Self { + Self { application, backend } + } + + pub async fn rotate_key(&self, key_id: &str) -> Result<()> { + self.backend.rotate_key(key_id).await + } + +} diff --git a/util/signing/signing-admin/src/lib.rs b/util/signing/signing-admin/src/lib.rs new file mode 100644 index 000000000..d4dc23dd5 --- /dev/null +++ b/util/signing/signing-admin/src/lib.rs @@ -0,0 +1,4 @@ +pub mod application; +pub mod backend; +pub mod key_manager; + diff --git a/util/signing/signing-admin/src/main.rs b/util/signing/signing-admin/src/main.rs new file mode 100644 index 000000000..c995beb60 --- /dev/null +++ b/util/signing/signing-admin/src/main.rs @@ -0,0 +1,21 @@ +use anyhow::Result; +use clap::Parser; + +mod cli; + +#[tokio::main] +async fn main() -> Result<()> { + let cli = cli::CLI::parse(); + + match cli.command { + cli::Commands::RotateKey { + canonical_string, + application_url, + backend, + } => { + cli::rotate_key::rotate_key(canonical_string, application_url, backend).await?; + } + } + + Ok(()) +}