Skip to content

Commit

Permalink
Pin Aiken, add tracing (#167)
Browse files Browse the repository at this point in the history
* Pin Aiken, add tracing

* Add tracing to checking account example

* Add debug to other contracts

* fmt

* Ignore rust-sec advisory
  • Loading branch information
MitchTurner authored Feb 25, 2024
1 parent c9e72c2 commit 8cfd04c
Show file tree
Hide file tree
Showing 18 changed files with 58 additions and 16 deletions.
1 change: 1 addition & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[advisories]
ignore = [
"RUSTSEC-2020-0071",
"RUSTSEC-2024-0013",
] # advisory IDs to ignore e.g. ["RUSTSEC-2019-0001", ...]
informational_warnings = ["unmaintained"] # warn for categories of informational advisories
severity_threshold = "low" # CVSS severity ("none", "low", "medium", "high", "critical")
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pallas-primitives = "0.20.0"
ogmios-client = { version = "0.1.0", git = "https://github.com/free-honey/ogmios-client.git" }
scrolls-client = { version = "0.1.0", git = "https://github.com/free-honey/scrolls-client.git" }
secrecy = "0.8.0"
tracing = "0.1.40"

[dependencies.blockfrost-http-client]
version = "0.0.14"
Expand All @@ -73,10 +74,10 @@ rand = "0.8.5"
sha2 = "0.10.6"

[patch.crates-io]
uplc = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", branch = "main"}
aiken = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", branch = "main"}
aiken-lang = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", branch = "main"}
aiken-project = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", branch = "main"}
uplc = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", tag = "v1.0.21-alpha"}
aiken = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", tag = "v1.0.21-alpha"}
aiken-lang = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", tag = "v1.0.21-alpha"}
aiken-project = { version = "1.0.21-alpha", git = "https://github.com/aiken-lang/aiken.git", tag = "v1.0.21-alpha"}

#[patch."https://github.com/aiken-lang/aiken.git"]
#aiken = { version = "1.0.3-alpha", path = "../aiken-lang/aiken/crates/aiken"}
Expand Down
2 changes: 1 addition & 1 deletion nau-scripts/aiken/mint_nft/plutus.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.21-alpha+30a6b77"
"version": "v1.0.21-alpha+4b04517"
}
},
"validators": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.21-alpha+30a6b77"
"version": "v1.0.21-alpha+4b04517"
}
},
"validators": [
Expand Down
3 changes: 3 additions & 0 deletions sample-dApps/always-succeeds-contract/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ mod tests;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct AlwaysSucceedsLogic;

#[derive(Debug)]
pub enum AlwaysSucceedsEndpoints {
Lock { amount: u64 },
Claim { output_id: OutputId },
}

#[derive(Debug)]
pub enum AlwaysSucceedsLookups {
ListActiveContracts { count: usize },
}

#[derive(Debug)]
pub enum AlwaysSucceedsLookupResponses {
ActiveContracts(Vec<Output<()>>),
}
Expand Down
1 change: 1 addition & 0 deletions sample-dApps/checking_account/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ serde_json = "1.0"
serde = { version = "1.0.143", features = ["derive"] }
thiserror = "1.0.24"
tokio = { version = "1.20.1", features = ["full"] }
tracing-subscriber = "0.3.18"
2 changes: 1 addition & 1 deletion sample-dApps/checking_account/checking/aiken.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ requirements = []
source = "github"

[etags]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1705105664, nanos_since_epoch = 813120107 }, "cf946239d3dd481ed41f20e56bf24910b5229ea35aa171a708edc2a47fc20a7b"]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1708887379, nanos_since_epoch = 415727333 }, "cf946239d3dd481ed41f20e56bf24910b5229ea35aa171a708edc2a47fc20a7b"]
10 changes: 5 additions & 5 deletions sample-dApps/checking_account/checking/plutus.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.21-alpha+30a6b77"
"version": "v1.0.21-alpha+4b04517"
}
},
"validators": [
Expand All @@ -24,8 +24,8 @@
"$ref": "#/definitions/Void"
}
},
"compiledCode": "59017c010000323232323232323232222325333006323253330083233232232323300100100222533301300114a026464a66602266016600e6eacc024c040c024c0400088cdc78008038a51133004004001301700230150013758600a6016600a6016010600200244a66601e002297ae0133010300d3011001330020023012001375c6002601000e4601e602000229444c8cc00cdd6180798081808180818081808180818081808180418011804002919b8f001002375c6002600e00c4601c00244646600200200644a66601c00229404c8c94ccc030c01400852889980200200098090011bae3010001149854cc01d2411856616c696461746f722072657475726e65642066616c73650013656323253330073370e9000000899191919299980798090010a4c2a6601800c2c6eb8c040004c040008dd7180700098030028a998040010b18041baa0044911b646174756d3a20436865636b696e674163636f756e74446174756d00230053754002ae695ce2ab9d5573caae7d5d02ba157441",
"hash": "7ada971e2ad6f1b9f6520731354f2facc6142a17f66110f04c425754"
"compiledCode": "5901bc010000323232323232323232222325333006323253330083233232232323300100100222533301300114a026464a66602266016600e6eacc024c040c024c0400088cdc78008038a51133004004001301700230150013758600a6016600a6016010600200244a66601e002297ae0133010300d3011001330020023012001375c6002601000e4601e602000229444c8cc00cdd6180798081808180818081808180818081808180418011804002919b8f001002375c6002600e00c4601c00244646600200200644a66601c00229404c8c94ccc030c01400852889980200200098090011bae3010001149854cc01d2411856616c696461746f722072657475726e65642066616c736500136563253330063370e9000000899191919299980718088010a4c2a660169201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c601e002601e0046eb8c034004c01401054cc01d24128436f6e73747220696e646578206469646e2774206d61746368206120747970652076617269616e740016300737540064600a6ea80055cd2b9c5573aaae7955cfaba05742ae89",
"hash": "caaafe29729380529f137971b3bc433b823cb5c4be9e00640c7c5899"
},
{
"title": "pull_validator.spend",
Expand All @@ -41,8 +41,8 @@
"$ref": "#/definitions/Void"
}
},
"compiledCode": "5909720100003232323232323232323222232325333008323232323232533300e00314a22646464a66602264a666024a66602400a26464646464a66602e66e1d200200113232533301900513371200c002266e20018004dd6980f000980a8010a503015001300b3013300b301330033013300b30130103370e9001180b1baa30083012300a301230023012300a301200f375a6004602202046032603460346034603460346034603400229404c8c8c8c8c94ccc05ccdc3a4004602c00226464646464a66603866e1d200000113232533301e3370e9002180e80089919192999810a999810a999810a999810a999810a99981099b87375a6020603e00466e00dd69808180f80f1bad300d301f01e13371e6eb8c054c07c008dd7180a980f80f0a5013370e6eb4c04cc07c008dd69809980f80f0a5013370e6eb4c034c07c008dd69806980f80f0a5013371e6eb8c030c07c008dd71806180f80f0a5013371e6eb8c048c07c008dd71809180f80f0a50132323301b00123371e0026eb8c03cc088084c03c004dd5980a980f8028a503301a00149012b657870656374206e65775f646174756d3a2050756c6c446174756d203d20756e74797065645f646174756d003025001301c001153301f4913065787065637420496e6c696e65446174756d28756e74797065645f646174756d29203d206f75747075742e646174756d0016300f301b0013022301a00214a060340026464a66603866e1d200200114c103d87a80001323300d3758601e603660266036030466ebcc050c070004008c088c068008c068004c8c94ccc070cdc3a4004002298103d87a800013374a9000198109809180d1808180d1811180d00125eb80c068004cc0280048cdd79808980c8008019bac300f3017300f3017014301e00130150011533018490123657870656374205370656e64286f75745f72656629203d206374782e707572706f73650016300a30140112301c301d301d301d301d301d0012301b301c301c301c301c001300100122533301800114bd7009980c980b180d00099801001180d8008a502301830193019301900113232323232323253330183370e9000180b800899191919299980e19b8748000c06c0044c8c8c94ccc07ccdc3a4008603c002264646464a66604666e1d200430220011323232323253330283370e00266e04008dd6980d1813012899baf00800414a060226eacc06cc094028c040dd5980d1812180d181200699808000a48140657870656374206f75747075745f6163636f756e745f646174756d3a20436865636b696e674163636f756e74446174756d203d206f75747075745f646174756d00302a001302100115330244912f65787065637420496e6c696e65446174756d286f75747075745f646174756d29203d206f75747075742e646174756d0016301430200053300c0014913e65787065637420696e7075745f6163636f756e745f646174756d3a20436865636b696e674163636f756e74446174756d203d20696e7075745f646174756d003026001301d00115330204913465787065637420496e6c696e65446174756d28696e7075745f646174756d29203d20696e7075742e6f75747075742e646174756d00163010301c3012301c0053023001301a001153301d49014665787065637420536f6d65286f757470757429203d2066696e645f6163636f756e745f6f757470757428646174756d2c206374782c206163636f756e745f6164647265737329001632323300d00123370e6464601c6601a002464646464a66604a66e3c010dd7180b1811811099b87001480085281bad302a001302a0013029002375c604e00260160026eacc048c0700052002323300100100222533302200114bd7009919299981019baf3016301e00200613302500233004004001133004004001302600230240013758601a60326022603202c60206030601c6030002603e002602c0022a6603292013365787065637420536f6d6528696e70757429203d2066696e645f6163636f756e745f696e70757428646174756d2c20637478290016323300800123370e6464601266010002464646464a66604066e3c010dd71808980f00e899b87001480085281bad302500130250013024002375c6044002600c0026eacc034c05cc034c05c00520023758601a602a601a602a0244646464a66603466e1d20020011480004dd69810180c001180c00099299980c99b8748008004530103d87a8000132323300100100222533302000114c103d87a800013232323253330203371e9110000213374a9000198129ba80014bd700998030030019bad3022003375c6040004604800460440026eacc07cc05c008c05c004c8cc004004008894ccc0740045300103d87a8000132323232533301d3371e9110000213374a9000198111ba60014bd700998030030019bab301f003375c603a0046042004603e0024464a66603066e1d200000113232323253330203023002149854cc07401858dd7181080098108011bae301f001301600315330190021630160022323300100100222533301b00114bd7009919991119198008008019129998108008801899198119ba733023375200c660466ea4dd71810000998119ba8375a604200297ae03300300330250023023001375c60340026eacc06c004cc00c00cc07c008c07400488c8cc00400400c894ccc06c00452f5c026464a666032600a00426603c6e9c008cc0100100044cc010010004c07c008dd6180e800980080091299980b8008a4000266e01200233002002301a00114a044646600200200644a666030002298103d87a8000132325333016300500213374a90001980d80125eb804cc010010004c070008c0680048c058c05cc05cc05cc05cc05cc05c0048c054c058c058004c8cc0180048cdc78009bae3003300d00c375860086016600660160104602660280026466008002466e3c004dd7180198058051bac300230093001300900623011001230103011301130113011301130113011301100122323300100100322533301000114a026464a66601c600a00429444cc010010004c050008dd718090008a4c2a660129211856616c696461746f722072657475726e65642066616c736500136563300100449110646174756d3a2050756c6c446174756d00223253330093370e900000089919191919191919191919191919299980d980f0010a4c2a660300202c6eb8c070004c070008dd7180d000980d0011bad30180013018002375a602c002602c0046eb4c050004c050008dd7180900098090011bae30100013007003153300a002163007002230063754002460086ea80055cd2b9c5573aaae7955cfaba05742ae89",
"hash": "d5202750204b65cbb68fa487dcd31593f43b8a49c0c68e8365a80723"
"compiledCode": "5907fa010000323232323232323232323232322223232533300b323232323232533301100314a22646464a66602864a66602aa66602a00a26464646464a66603466e1d200200113232533301c00513371200c002266e20018004dd69810800980a8010a503018001300b3013300b301330033013300b30130103370e9001180c9baa30083012300a301230023012300a301200f375a6004602202046038603a603a603a603a603a603a603a00229404c8c8c8c8c94ccc068cdc3a4004603200226464646464a66603e66e1d20000011323253330213370e90021810000899191929998122999812299981229998122999812299981219b87375a6020603e00466e00dd69808180f80f1bad300d301f01e13371e6eb8c054c07c008dd7180a980f80f0a5013370e6eb4c04cc07c008dd69809980f80f0a5013370e6eb4c034c07c008dd69806980f80f0a5013371e6eb8c030c07c008dd71806180f80f0a5013371e6eb8c048c07c008dd71809180f80f0a50132323301b00123371e0026eb8c03cc088084c03c004dd5980a980f8028a50301a0013028001301c001153302201f16300f301b0013025301a00214a0603a0026464a66603e66e1d200200114c0103d87a80001323300d3758601e603660266036030466ebcc050c070004008c094c068008c074004c8c94ccc07ccdc3a4004002298103d87a800013374a9000198121809180d1808180d1812980d00125eb80c074004cc0280048cdd79808980c8008019bac300f3017300f301701430210013015001153301b01816300a30140112301f302030203020302030200012301e301f301f301f301f001300100122533301b00114bd7009980e180c980e80099801001180f0008a502301b301c301c301c001132323232323232533301b3370e9000180d000899191919299980f99b8748000c0780044c8c8c94ccc088cdc3a40086042002264646464a66604c66e1d2004302500113232323232533302b3370e00266e04008dd6980d1813012899baf00800414a060226eacc06cc094028c040dd5980d1812180d18120069808000981680098108008a998138120b180a181000298060009814800980e8008a998118100b1808180e1809180e0029813000980d0008a9981000e8b191919806800919b873232300e3300d00123232323253330283371e0086eb8c058c08c0884cdc3800a40042940dd69816800981680098160011bae302a001300b001375660246038002900119198008008011129998128008a5eb804c8c94ccc08ccdd7980b180f00100309981400119802002000899802002000981480118138009bac300d30193011301901630103018300e301800130220013016001153301c01916323300800123370e6464601266010002464646464a66604666e3c010dd71808980f00e899b87001480085281bad302800130280013027002375c604a002600c0026eacc034c05cc034c05c00520023758601a602a601a602a0244646464a66603a66e1d20020011480004dd69811980c001180d80099299980e19b8748008004530103d87a8000132323300100100222533302300114c103d87a800013232323253330233371e9110000213374a9000198141ba80014bd700998030030019bad3025003375c6046004604e004604a0026eacc088c05c008c068004c8cc004004008894ccc0800045300103d87a800013232323253330203371e9110000213374a9000198129ba60014bd700998030030019bab3022003375c604000460480046044002464a66603466e1d200000113232323253330223025002149854cc07c06c58dd7181180098118011bae30210013015002153301b0161630180012323300100100222533301e00114bd7009919991119198008008019129998120008801899198131ba733026375200c6604c6ea4dd71811800998131ba8375a604800297ae03300300330280023026001375c603a0026eacc078004cc00c00cc088008c08000488c8cc00400400c894ccc07800452f5c026464a666038600a0042660426e9c008cc0100100044cc010010004c088008dd61810000980080091299980d0008a4000266e01200233002002301d00114a044646600200200644a6660360022980103d87a8000132325333019300500213374a90001980f00125eb804cc010010004c07c008c0740048c064c068c068c068c068c068c0680048c060c064c064004c8cc0180048cdc78009bae3003300d00c375860086016600660160104602c602e0026466008002466e3c004dd7180198058051bac300230093001300900623014001230133014301430143014301430143014301400122323300100100322533301300114a026464a666022600a00429444cc010010004c05c008dd7180a8008a4c2a660189211856616c696461746f722072657475726e65642066616c736500136563001004232533300b3370e900000089919191919191919191919191919299980e98100010a4c2a6603402c2c6eb8c078004c078008dd7180e000980e0011bad301a001301a002375a603000260300046eb4c058004c058008dd7180a000980a0011bae30120013006002153300c007163009001230093754002920128436f6e73747220696e646578206469646e2774206d61746368206120747970652076617269616e74004901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564004901244578706563746564206f6e20696e636f727265637420436f6e7374722076617269616e7400230043754002ae695ce2ab9d5573caae7d5d02ba157441",
"hash": "bb1d874037cf417894bc9bb2387fa1de29cb6143086b1581dfdf98ed"
},
{
"title": "spend_token_policy.mint",
Expand Down
3 changes: 3 additions & 0 deletions sample-dApps/checking_account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub const SPEND_TOKEN_ASSET_NAME: &str = "SPEND TOKEN";
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TimeLockedLogic;

#[derive(Debug)]
pub enum CheckingAccountEndpoints {
// Owner Endpoints
/// Create a new checking account
Expand Down Expand Up @@ -65,10 +66,12 @@ pub enum CheckingAccountEndpoints {
},
}

#[derive(Debug)]
pub enum CheckingAccountLookups {
MyAccounts,
}

#[derive(Debug)]
pub enum CheckingAccountLookupResponses {
MyAccounts(Vec<Account>),
}
Expand Down
1 change: 1 addition & 0 deletions sample-dApps/checking_account/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum ActionParams {

#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
let args = Args::parse();
match args.action {
ActionParams::Init { starting_ada } => init_checking_account_impl(starting_ada).await?,
Expand Down
1 change: 1 addition & 0 deletions sample-dApps/free-minting-contract/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod script;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FreeMintingLogic;

#[derive(Debug)]
pub enum FreeMintingEndpoints {
Mint { amount: u64 },
}
Expand Down
3 changes: 3 additions & 0 deletions sample-dApps/game-contract/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ mod tests;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct GameLogic;

#[derive(Debug)]
pub enum GameEndpoints {
Lock { amount: u64, secret: String },
Guess { output_id: OutputId, guess: String },
}

#[derive(Debug)]
pub enum GameLookups {
ListActiveContracts { count: usize },
}

#[derive(Debug)]
pub enum GameLookupResponses {
ActiveContracts(Vec<Output<HashedString>>),
}
Expand Down
1 change: 1 addition & 0 deletions sample-dApps/mint_nft/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use naumachia::logic::error::{SCLogicError, SCLogicResult};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MintNFTLogic;

#[derive(Debug)]
pub enum MintNFTEndpoints {
Mint,
}
Expand Down
3 changes: 3 additions & 0 deletions sample-dApps/time-locked-contract/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ pub mod script;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TimeLockedLogic;

#[derive(Debug)]
pub enum TimeLockedEndpoints {
Lock { amount: u64, after_secs: i64 },
Claim { output_id: OutputId },
}

#[derive(Debug)]
pub enum TimeLockedLookups {
ListActiveContracts { count: usize },
}

#[derive(Debug)]
pub enum TimeLockedLookupResponses {
ActiveContracts(Vec<Output<i64>>),
}
Expand Down
2 changes: 1 addition & 1 deletion sample-dApps/time-locked-contract/time_locked/plutus.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.21-alpha+30a6b77"
"version": "v1.0.21-alpha+4b04517"
}
},
"validators": [
Expand Down
28 changes: 25 additions & 3 deletions src/smart_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,42 @@ where
impl<Logic, Record> SmartContractTrait for SmartContract<Logic, Record>
where
Logic: SCLogic + Eq + Debug + Send + Sync,
Logic::Endpoints: Debug,
Logic::Lookups: Debug,
Logic::LookupResponses: Debug,
Record: LedgerClient<Logic::Datums, Logic::Redeemers> + Send + Sync,
{
type Endpoint = Logic::Endpoints;
type Lookup = Logic::Lookups;
type LookupResponse = Logic::LookupResponses;

async fn hit_endpoint(&self, endpoint: Logic::Endpoints) -> Result<TxId> {
tracing::info!("Hitting smart contract endpoint: {:?}", &endpoint);
let tx_actions = Logic::handle_endpoint(endpoint, &self.ledger_client).await?;
let tx = tx_actions.to_unbuilt_tx()?;
let tx_id = self.ledger_client.issue(tx).await?;
Ok(tx_id)
match self.ledger_client.issue(tx).await {
Ok(tx_id) => {
tracing::info!("Successfully submitted transaction with id: {:?}", &tx_id);
Ok(tx_id)
}
Err(err) => {
tracing::error!("Failed to submit transaction: {:?}", err);
Err(err.into())
}
}
}

async fn lookup(&self, lookup: Self::Lookup) -> Result<Self::LookupResponse> {
Ok(Logic::lookup(lookup, &self.ledger_client).await?)
tracing::info!("Looking up smart contract information: {:?}", &lookup);
match Logic::lookup(lookup, &self.ledger_client).await {
Ok(res) => {
tracing::info!("Successfully queried information: {:?}", &res);
Ok(res)
}
Err(err) => {
tracing::error!("Failed to query information: {:?}", err);
Err(err.into())
}
}
}
}
1 change: 1 addition & 0 deletions tests/always_mints_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl<R> MintingPolicy<R> for AlwaysMintsPolicy {
#[derive(Debug, Clone, Eq, PartialEq)]
struct AlwaysMintsSmartContract;

#[derive(Debug)]
enum Endpoint {
Mint { amount: u64 },
}
Expand Down
1 change: 1 addition & 0 deletions tests/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use pallas_addresses::Address;
#[derive(Debug, Clone, Eq, PartialEq)]
struct TransferADASmartContract;

#[derive(Debug)]
enum Endpoint {
Transfer { amount: u64, recipient: Address },
}
Expand Down

0 comments on commit 8cfd04c

Please sign in to comment.