diff --git a/.vimspector.json b/.vimspector.json new file mode 100644 index 0000000..c10caf2 --- /dev/null +++ b/.vimspector.json @@ -0,0 +1,27 @@ +{ + "configurations": { + ": Launch": { + "adapter": "CodeLLDB", + "configuration": { + "name": "", + "type": "lldb", + "request": "launch", + "program": "${workspaceRoot}/target/debug/deps/vyper_rs-686403a730734cd8", + "cwd": "${workspaceRoot}", + "externalConsole": true, + "stopAtEntry": true, + "MIMode": "gdb" + } + }, + ": Attach": { + "adapter": "CodeLLDB", + "configuration": { + "name": ": Attach", + "type": "lldb", + "request": "attach", + "program": "${workspaceRoot}/target/debug/deps/vyper_rs-686403a730734cd8", + "MIMode": "gdb" + } + } + } +} diff --git a/Cargo.lock b/Cargo.lock index 774288c..b1177ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3350,7 +3350,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "vyper-rs" version = "1.0.0" dependencies = [ - "anyhow", "hex", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 9e12651..1bdf9da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,16 @@ license = "MIT" keywords = ["Crypto", "Vyper", "EVM", "Compilers"] description = "A Rust library to interact with the Vyper compiler!" repository = "https://github.com/crypdoughdoteth/vyper-rs/" +exclude = [ + "examples/contracts" +] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.72" hex = "0.4.3" serde = {version = "1.0.171", features = ["derive"]} serde_json = "1.0.102" -tokio = { version = "1.29.1", features = ["rt"] } +tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } +[dev-dependencies] tokio-test = "0.4.2" + diff --git a/examples/contracts/src/compile.rs b/examples/contracts/src/compile.rs index dbee721..76aac65 100644 --- a/examples/contracts/src/compile.rs +++ b/examples/contracts/src/compile.rs @@ -4,8 +4,7 @@ use vyper_rs::vyper::Vyper; pub fn compile_and_generate_bindings() -> Result<(), Box> { let cpath: PathBuf = PathBuf::from("../../multisig.vy"); - let abi: PathBuf = PathBuf::from("./my_abi.json"); - let contract = Vyper::new(cpath, abi); + let contract = Vyper::new(&cpath); contract.gen_abi()?; println!("Generating bindings for {contract}\n"); diff --git a/examples/contracts/src/deploy.rs b/examples/contracts/src/deploy.rs index e68c9ca..5d2438a 100644 --- a/examples/contracts/src/deploy.rs +++ b/examples/contracts/src/deploy.rs @@ -16,8 +16,7 @@ use vyper_rs::vyper::Vyper; pub async fn deploy() -> Result<(), Box> { let cpath: PathBuf = PathBuf::from("../../multisig.vy"); - let abi: PathBuf = PathBuf::from("./my_abi.json"); - let mut contract = Vyper::new(cpath, abi); + let mut contract = Vyper::new(&cpath); contract.compile()?; contract.gen_abi()?; let anvil = Anvil::new().spawn(); diff --git a/examples/contracts/src/venv.rs b/examples/contracts/src/venv.rs index 83cfcca..42e4bdc 100644 --- a/examples/contracts/src/venv.rs +++ b/examples/contracts/src/venv.rs @@ -1,11 +1,11 @@ -use std::{error::Error, path::PathBuf}; -use vyper_rs::{venv::Venv, vyper::Vyper}; +use std::{error::Error, path::Path}; +use vyper_rs::venv::Venv; pub fn venv_example() -> Result<(), Box> { - let cpath: PathBuf = PathBuf::from("../../multisig.vy"); - let abi: PathBuf = PathBuf::from("./my_abi.json"); - let venv = Venv::new().init()?.ivyper_venv(None)?; - let mut contract = Vyper::new(cpath, abi); - venv.compile(&mut contract)?; + let mut contract = Venv::default() + .init()? + .ivyper_venv(None)? + .vyper(Path::new("../../multisig.vy")); + contract.compile()?; Ok(()) } diff --git a/multisig.vy b/multisig.vy new file mode 100644 index 0000000..7376677 --- /dev/null +++ b/multisig.vy @@ -0,0 +1,125 @@ +# @version ^0.3.3 +# Multiple Signature Contract + +event Deposit: + sender: indexed(address) + amount: uint256 + bal: uint256 +event SubmitTransaction: + owner: indexed(address) + txIndex: indexed(uint256) + to: indexed(address) + value: uint256 + data: bytes32 +event ConfirmTransaction: + owner: indexed(address) + txIndex: indexed(uint256) +event RevokeConfirmation: + owner: indexed(address) + txIndex: indexed(uint256) +event ExecuteTransaction: + owner: indexed(address) + txIndex: indexed(uint256) + +owners: DynArray[address, 10] +isOwner: HashMap[address, bool] +numConfirmationsRequired: constant(uint256) = 1 + + +struct Transaction: + to: address + val: uint256 + data: bytes32 + fnSel: String[32] + executed: bool + numConfirmations: uint256 + + +isConfirmed: public(HashMap[uint256, HashMap[address, bool]]) + +transactions: DynArray[Transaction, 100000] + + +@external +def __init__ (_owners: DynArray[address,10]): + assert len(_owners) > 0, "Error: No Owners" + assert numConfirmationsRequired > 0 and numConfirmationsRequired <= len(_owners) + for o in _owners: + assert o != empty(address) + assert self.isOwner[o] == False, "Owner Not Unique" + self.isOwner[o] = True + self.owners.append(o) + +@external +@payable +def __default__(): + log Deposit(msg.sender, msg.value, self.balance) + +@external +def submitTransaction( _to: address, _val: uint256, _data: bytes32, _fnSel: String[32]): + assert self.isOwner[msg.sender] == True, "Not an Owner" + txIndex: uint256 = len(self.transactions) + self.transactions.append(Transaction({to:_to, val:_val, data: _data, fnSel: _fnSel, executed: False, numConfirmations: 0})) + +@external +def confirmTransaction(txIndex: uint256): + assert self.isOwner[msg.sender]==True, "Not an Owner" + assert txIndex < len(self.transactions), "Does Not Exist" + assert self.transactions[txIndex].executed == False, "Transaction Already Executed" + assert self.isConfirmed[txIndex][msg.sender], "Transactions Already Confirmed" + self.transactions[txIndex].numConfirmations += 1 + self.isConfirmed[txIndex][msg.sender] = True + log ConfirmTransaction(msg.sender, txIndex) + +@payable +@external +def executeTransaction(txIndex: uint256) -> Bytes[32]: + assert self.isOwner[msg.sender]==True, "Not an Owner" + assert txIndex < len(self.transactions), "Does Not Exist" + assert self.transactions[txIndex].executed == False, "Transaction Already Executed" + assert self.transactions[txIndex].numConfirmations >= numConfirmationsRequired, "Insufficent Confirmations" + self.transactions[txIndex].executed = True + success: bool = False + response: Bytes[32] = b"" + functionSelector: Bytes[32] = convert(self.transactions[txIndex].fnSel, Bytes[32]) + success, response = raw_call( + self.transactions[txIndex].to, + #add field for function selector, seperate from data + _abi_encode(self.transactions[txIndex].data, (convert(keccak256(self.transactions[txIndex].fnSel), bytes4))), + max_outsize=32, + value = self.transactions[txIndex].val, + revert_on_failure = False + ) + assert success + return response + +@nonpayable +@external +def revokeConfirmation(_txIndex: uint256): + assert _txIndex < len(self.transactions), "Does Not Exist" + assert self.transactions[_txIndex].executed == False, "Transaction Already Executed" + self.transactions[_txIndex].numConfirmations -= 1 + self.isConfirmed[_txIndex][msg.sender] = False + log RevokeConfirmation(msg.sender, _txIndex) + +@view +@external +def getOwners() -> DynArray[address, 10]: + return self.owners + +@view +@external +def getTransactionCount() -> uint256: + return len(self.transactions) + +@view +@external +def getTransaction(_txIndex: uint256) -> (address, uint256, bytes32, String[32], bool, uint256): + return( + self.transactions[_txIndex].to, + self.transactions[_txIndex].val, + self.transactions[_txIndex].data, + self.transactions[_txIndex].fnSel, + self.transactions[_txIndex].executed, + self.transactions[_txIndex].numConfirmations + ) diff --git a/src/lib.rs b/src/lib.rs index 781bb56..9c599e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,15 +10,20 @@ pub mod vyper_errors; #[cfg(test)] mod test { + use self::{vyper::VyperStack, vyper_errors::VyperErrors}; + use super::*; - use crate::vyper::{Evm, Vyper, Vypers}; - use std::path::PathBuf; + use crate::{ + utils::Blueprint, + vyper::{Evm, Vyper, Vypers}, + }; + use std::path::{Path, PathBuf}; #[test] fn basic() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let mut vyper_contract = Vyper::new(path, abi_path); + let mut vyper_contract = Vyper::new(&path); + println!("\n{:#?}\n", vyper_contract.abi); vyper_contract.compile().unwrap(); vyper_contract.gen_abi().unwrap(); } @@ -26,9 +31,8 @@ mod test { #[test] fn compile_version() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let mut vyper_contract = Vyper::new(path, abi_path); - vyper_contract.compile_ver(Evm::Shanghai).unwrap(); + let mut vyper_contract = Vyper::new(&path); + vyper_contract.compile_ver(&Evm::Shanghai).unwrap(); } #[test] @@ -38,12 +42,7 @@ mod test { let path2: PathBuf = PathBuf::from("./multisig.vy"); let path3: PathBuf = PathBuf::from("./multisig.vy"); let path4: PathBuf = PathBuf::from("./multisig.vy"); - let abi: PathBuf = PathBuf::from("./abi1.json"); - let abi2: PathBuf = PathBuf::from("./abi2.json"); - let abi3: PathBuf = PathBuf::from("./abi3.json"); - let abi4: PathBuf = PathBuf::from("./abi4.json"); - let mut vyper_contracts = - Vypers::new(vec![path, path2, path3, path4], vec![abi, abi2, abi3, abi4]); + let mut vyper_contracts = Vypers::new(vec![path, path2, path3, path4]); vyper_contracts .compile_many_ver(Evm::Shanghai) .await @@ -59,12 +58,7 @@ mod test { let path2: PathBuf = PathBuf::from("./multisig.vy"); let path3: PathBuf = PathBuf::from("./multisig.vy"); let path4: PathBuf = PathBuf::from("./multisig.vy"); - let abi: PathBuf = PathBuf::from("./abi1.json"); - let abi2: PathBuf = PathBuf::from("./abi2.json"); - let abi3: PathBuf = PathBuf::from("./abi3.json"); - let abi4: PathBuf = PathBuf::from("./abi4.json"); - let mut vyper_contracts = - Vypers::new(vec![path, path2, path3, path4], vec![abi, abi2, abi3, abi4]); + let mut vyper_contracts = Vypers::new(vec![path, path2, path3, path4]); vyper_contracts.compile_many().await.unwrap(); assert!(!vyper_contracts.bytecode.is_none()); }) @@ -73,46 +67,41 @@ mod test { #[test] fn interface() { let path = PathBuf::from("./multisig.vy"); - let abi_path: PathBuf = PathBuf::from("./abi.json"); - let vyper_contract = Vyper::new(path, abi_path); + let vyper_contract = Vyper::new(&path); vyper_contract.interface().unwrap(); } #[test] fn storage() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let vyper_contract = Vyper::new(path, abi_path); + let vyper_contract = Vyper::new(&path); vyper_contract.storage_layout().unwrap(); } #[test] fn opcodes() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let vyper_contract = Vyper::new(path, abi_path); + let vyper_contract = Vyper::new(&path); vyper_contract.opcodes().unwrap(); } #[test] fn ast() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let vyper_contract = Vyper::new(path, abi_path); + let vyper_contract = Vyper::new(&path); vyper_contract.ast().unwrap(); } #[test] fn bp() { let path = PathBuf::from("./multisig.vy"); - let abi_path = PathBuf::from("./abi.json"); - let mut vyper_contract = Vyper::new(path, abi_path); - Vyper::compile_blueprint(&mut vyper_contract).unwrap(); + let mut vyper_contract = Vyper::new(&path); + vyper_contract.compile_blueprint().unwrap(); } #[test] fn exists() { - assert_eq!(true, Vyper::exists()) + assert_eq!(true, Vyper::exists(&Vyper::new(Path::new("./multisig.vy")))) } #[test] @@ -120,178 +109,156 @@ mod test { let case1 = b"\xFE\x71\x00\x00"; let case2 = b"\xFE\x71\x01\x07\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"; let case3 = b"\xFE\x71\x02\x01\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"; - let (a, b, c) = utils::parse_blueprint(case1).unwrap(); - assert_eq!((0u8, None, vec![0]), (a, b, c)); - let (a2, b2, c2) = utils::parse_blueprint(case2).unwrap(); - assert_eq!( - (0u8, Some(vec![255, 255, 255, 255, 255, 255, 255]), vec![0]), - (a2, b2, c2) - ); - let (a3, b3, c3) = utils::parse_blueprint(case3).unwrap(); - assert_eq!( - ( - 0u8, - Some(vec![ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 - ]), - vec![0] - ), - (a3, b3, c3) - ); + { + let Blueprint { + erc_version, + preamble_data, + initcode, + } = utils::parse_blueprint(case1).unwrap(); + assert_eq!((0u8, None, vec![0]), (erc_version, preamble_data, initcode)); + } + { + let Blueprint { + erc_version, + preamble_data, + initcode, + } = utils::parse_blueprint(case2).unwrap(); + assert_eq!( + (0u8, Some(vec![255, 255, 255, 255, 255, 255, 255]), vec![0]), + (erc_version, preamble_data, initcode) + ); + } + { + let Blueprint { + erc_version, + preamble_data, + initcode, + } = utils::parse_blueprint(case3).unwrap(); + assert_eq!( + ( + 0u8, + Some(vec![ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255 + ]), + vec![0] + ), + (erc_version, preamble_data, initcode) + ); + } } use crate::venv::{Ready, Venv}; #[test] fn venv_test() { - let venv = Venv::new().init().unwrap().ivyper_venv(None).unwrap(); - let mut contract = - Vyper::new(PathBuf::from("./multisig.vy"), PathBuf::from("./abi.json")); - venv.compile(&mut contract).unwrap(); + let mut contract = Venv::default() + .init() + .unwrap() + .ivyper_venv(None) + .unwrap() + .vyper(Path::new("./multisig.vy")); + contract.compile().unwrap(); } #[test] fn version_detect() { - Vyper::get_version().unwrap(); + Vyper::get_version(&Vyper::new(Path::new("./multisig.vy"))).unwrap(); } #[test] fn vyper_macro_test() { - let c = vyper!("./multisig.vy", "./abi.json"); - let c_assertion = - Vyper::new(PathBuf::from("./multisig.vy"), PathBuf::from("./abi.json")); + let c = vyper!("./multisig.vy"); + let c_assertion = Vyper::new(Path::new("./multisig.vy")); assert_eq!(c, c_assertion); - let c2_assertion = vec![ - Vyper::new(PathBuf::from("./multisig.vy"), PathBuf::from("./abi.json")), - Vyper::new(PathBuf::from("./multisig.vy"), PathBuf::from("./abi.json")), - ]; - let c2 = vyper!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); + let c2_assertion = Vypers::from(vec![ + Vyper::new(Path::new("./multisig.vy")), + Vyper::new(Path::new("./multisig.vy")), + ]); + let c2 = vyper!("./multisig.vy", "./multisig.vy"); assert_eq!(c2, c2_assertion); } #[test] fn vypers_macro_test() { - let vys_assertion = Vypers::new( - vec![ - PathBuf::from("./multisig.vy"), - PathBuf::from("./multisig.vy"), - ], - vec![PathBuf::from("./abi.json"), PathBuf::from("./abi.json")], - ); - let vys = vypers!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); + let vys_assertion = Vypers::new(vec![ + PathBuf::from("./multisig.vy"), + PathBuf::from("./multisig.vy"), + ]); + let vys = vyper!("./multisig.vy", "./multisig.vy"); assert_eq!(vys, vys_assertion); } #[test] - fn compile_macro_test() { - let mut contract_assertion = vyper!("./multisig.vy", "./abi.json"); + fn compile_macro_test() -> Result<(), VyperErrors> { + let mut contract_assertion = vyper!("./multisig.vy"); contract_assertion.compile().unwrap(); - let contract = compile!("./multisig.vy", "./abi.json"); + let contract = compile!("./multisig.vy"); assert_eq!(contract, contract_assertion); + Ok(()) } - #[test] - fn compile_mt_macro_test() { - tokio_test::block_on(async { - let mut vys_assertion = - vypers!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - vys_assertion.compile_many().await.unwrap(); - let vys = - compile!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - assert_eq!(vys, vys_assertion); - }) - } - - #[test] - fn compabi_macro_test() { - let c_assertion = compile!("./multisig.vy", "./abi.json"); - c_assertion.gen_abi().unwrap(); - let c = abi!("./multisig.vy", "./abi.json"); - assert_eq!(c, c_assertion); - } - - #[test] - fn compabi_mt_macro_test() { - tokio_test::block_on(async { - let vys_assertion = - compile!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - vys_assertion.get_abi_many().await.unwrap(); - let vys = abi!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - assert_eq!(vys, vys_assertion); - }) + #[tokio::test] + async fn compile_mt_macro_test() -> Result<(), VyperErrors> { + let mut vys_assertion = vyper!("./multisig.vy", "./multisig.vy"); + vys_assertion.compile_many().await.unwrap(); + let vys = compile!("./multisig.vy", "./multisig.vy"); + assert_eq!(vys, vys_assertion); + Ok(()) } #[test] - fn compabijson_macro_test() { - let c_assertion = compile!("./multisig.vy", "./abi.json"); + fn compabijson_macro_test() -> Result<(), VyperErrors> { + let c_assertion = compile!("./multisig.vy"); let abi = c_assertion.get_abi().unwrap(); - let c = abi!(get "./multisig.vy", "./abi.json"); - assert_eq!(c, (c_assertion, abi)); + let c = abi!("./multisig.vy"); + assert_eq!(c, abi); + Ok(()) } #[test] - fn compabijson_mt_macro_test() { + fn compabijson_mt_macro_test() -> Result<(), VyperErrors> { tokio_test::block_on(async { - let vys_assertion = - compile!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); + let vys_assertion = compile!("./multisig.vy", "./multisig.vy"); let abis = vys_assertion.get_abi_many().await.unwrap(); - let vys = - abi!(get "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - assert_eq!(vys, (vys_assertion, abis)); + let vys = abi!("./multisig.vy", "./multisig.vy"); + assert_eq!(vys, abis); + Ok(()) }) } #[test] - fn venv_macro_test() { + fn venv_macro_test() -> Result<(), VyperErrors> { let _: Venv = venv!(); let _: Venv = venv!("0.3.10"); + Ok(()) } #[test] - fn venv_compile_macro_test() { - let (_, _): (Vyper, Venv) = compile!(venv "./multisig.vy", "./abi.json"); - let _: Vyper = compile!(paris "./multisig.vy", "./abi.json"); - let (_, _): (Vyper, Venv) = - compile!(venv paris "./multisig.vy", "./abi.json"); - tokio_test::block_on(async { - let _ = compile!(venv "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = compile!(paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = compile!(venv paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - }) - } - #[test] - fn more_abi_tests() { - tokio_test::block_on(async { - let _ = - abi!(venv "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = abi!(venv get "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = - abi!(paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = abi!(venv paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = abi!(get paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = abi!(venv get paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); - let _ = abi!(venv "./multisig.vy", "./abi.json"); - let _ = abi!(venv get "./multisig.vy", "./abi.json"); - let _ = abi!(paris "./multisig.vy", "./abi.json"); - let _ = abi!(venv paris "./multisig.vy", "./abi.json"); - let _ = abi!(get paris "./multisig.vy", "./abi.json"); - let _ = abi!(venv get paris "./multisig.vy", "./abi.json"); - }); + fn test_stack_mt() -> Result<(), VyperErrors> { + let mut stack = [ + Vyper::new(Path::new("./multsig.vy")), + Vyper::new(Path::new("./multsig.vy")), + ]; + let mut contracts = VyperStack(&mut stack); + contracts.gen_abi_many()?; + contracts.compile_many()?; + Ok(()) } } diff --git a/src/macros.rs b/src/macros.rs index f5d63a7..5f4f7f5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -14,165 +14,93 @@ /// use vyper_rs::*; /// use std::path::PathBuf; /// fn try_me() { -/// let _: Vyper = vyper!("./multisig.vy", "./abi.json"); -/// let _: Vec = vyper!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); +/// let _: Vyper = vyper!("./multisig.vy"); +/// let _: Vypers = vyper!("./multisig.vy", "./multisig.vy"); /// } /// ``` #[macro_export] macro_rules! vyper { - ($p1: expr, $p2: expr) => { - Vyper {path_to_code: PathBuf::from($p1), bytecode: None, abi: PathBuf::from($p2)} + + ($p1: expr) => { + Vyper::new(Path::new($p1)) }; - ($($p1: expr, $p2: expr),+) => { + ($($p1: expr),+) => { { let mut contracts: Vec = vec![]; $( - let v = vyper!($p1, $p2); + let v = vyper!($p1); contracts.push(v); )+ - contracts + Vypers::from(contracts) } }; } -/// The `vypers!` macro is used to construct the Vypers type without the boilerplate. -/// -/// Input: any length sequence of paired string literals (one for the contract, one for the abi (or desired path)). -/// -/// ```rust -/// use vyper_rs::vyper::*; -/// use vyper_rs::*; -/// use std::path::PathBuf; -/// fn try_me() { -/// let _: Vypers = vypers!("./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); -/// } -/// ``` -#[macro_export] -macro_rules! vypers{ - ($($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let cs: Vypers = contracts.into(); - cs - } - }; -} /// The `compile!` macro is used to compile one more more Vyper contracts. /// /// Input: any length sequence of paired string literals (one for the contract, one for the abi (or desired path)). /// -/// Keywords: paris, venv. -/// -/// paris - compile contract for the Paris version of the EVM. +/// Keywords: venv. /// /// venv - compile contract using an instance of the Vyper compiler inside a venv. /// -/// These keywords can even be used together! -/// /// ```rust /// use vyper_rs::venv::*; /// use vyper_rs::vyper::*; /// use vyper_rs::*; /// use std::path::PathBuf; /// async fn try_me() { -/// let _: (Vypers, Venv) = compile!(venv paris "./multisig.vy", "./abi.json", "./multisig.vy", "./abi.json"); -/// let _: (Vyper, Venv) = compile!(venv "./multisig.vy", "./abi.json"); -/// let _: Vyper = compile!("./multisig.vy", "./abi.json"); -/// let _: Vyper = compile!(paris "./multisig.vy", "./abi.json"); +/// let _: Vyper = compile!(venv "./multisig.vy"); +/// let _: Vyper = compile!("./multisig.vy"); +/// let _: Vypers = compile!(venv "./multisig.vy", "./multisig.vy"); +/// let _: Vypers = compile!("./multisig.vy", "./multisig.vy"); /// } /// ``` #[macro_export] macro_rules! compile { // classic, simple - ($p1: expr, $p2: expr) => { + ($p1: expr) => { { - let mut vy: Vyper = vyper!($p1, $p2); - vy.compile().unwrap(); + let mut vy: Vyper = vyper!($p1); + vy.compile()?; vy } }; // a twist on the classic: compile inside a venv with keyword venv - (venv $p1: expr, $p2: expr) => { - { - let venv: Venv = venv!(); - let mut vy: Vyper = vyper!($p1, $p2); - venv.compile(&mut vy).unwrap(); - (vy, venv) - } - }; - // EVM Target: Paris - (paris $p1: expr, $p2: expr) => { - { - let mut vy: Vyper = vyper!($p1, $p2); - vy.compile_ver(Evm::Paris).unwrap(); - vy - } - }; - // compile to paris inside venv - (venv paris $p1: expr, $p2: expr) => { + (venv $p1: expr) => { { - let venv: Venv = venv!(); - let mut vy: Vyper = vyper!($p1, $p2); - venv.compile_ver(&mut vy, Evm::Paris).unwrap(); - (vy, venv) + let mut contract = Venv::default() + .init()? + .ivyper_venv(None)? + .vyper(Path::new("../../multisig.vy")); + contract.compile()?; + contract } }; // compile many - ($($p1: expr, $p2: expr),+) => { + ($($p1: expr),+) => { { let mut contracts: Vec = vec![]; $( - let v = vyper!($p1, $p2); + let v = vyper!($p1); contracts.push(v); )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many().await.unwrap(); + let mut cs: Vypers = Vypers::from(contracts); + cs.compile_many().await?; cs } }; // compile many in venv - (venv $($p1: expr, $p2: expr),+) => { + (venv $($p1: expr),+) => { { - let mut contracts: Vec = vec![]; + let mut paths: Vec = vec![]; $( - let v = vyper!($p1, $p2); - contracts.push(v); + let v = PathBuf::from($p1); + paths.push(v); )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many(&mut cs).await.unwrap(); - (cs, venv) - } - }; - // Compile many for Paris - (paris $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many_ver(Evm::Paris).await.unwrap(); - cs - } - }; - // compile many for paris inside venv - (venv paris $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many_ver(&mut cs, Evm::Paris).await.unwrap(); - (cs, venv) + let mut contracts = Venv::default().init()?.ivyper_venv(None)?.vypers(contracts); + contracts.compile_many().await?; + contracts } }; } @@ -209,184 +137,42 @@ macro_rules! compile { #[macro_export] macro_rules! abi { // OG matcher - ($p1: expr, $p2: expr) => { - { - let c: Vyper = compile!($p1, $p2); - c.gen_abi().unwrap(); - c - } - }; - // OG matcher with a venv - (venv $p1: expr, $p2: expr) => { - { - let (c, v): (Vyper, Venv) = compile!(venv $p1, $p2); - v.gen_abi(&c).unwrap(); - (c, v) - } - }; // return the ABI as json instead of creating a file - (get $p1: expr, $p2: expr) => { - { - let c: Vyper = compile!($p1, $p2); - let abi = c.get_abi().unwrap(); - (c, abi) - } - }; - // returns the ABI as JSON, Vypers struct, and Venv - (venv get $p1: expr, $p2: expr) => { - { - let (c, v): (Vyper, Venv) = compile!(venv $p1, $p2); - let abi = v.get_abi(&c).unwrap(); - (c, abi, v) - } - }; - // gen abi, compile for paris - (paris $p1: expr, $p2: expr) => { - { - let c: Vyper = compile!(paris $p1, $p2); - c.gen_abi().unwrap(); - c - } - }; - // return abi in json form, compile for paris - (get paris $p1: expr, $p2: expr) => { - { - let c: Vyper = compile!(paris $p1, $p2); - let abi = c.get_abi().unwrap(); - (c, abi) - } - }; - // gen abi, compile for paris - (venv paris $p1: expr, $p2: expr) => { + ($p1: expr) => { { - let (c, v): (Vyper, Venv) = compile!(venv paris $p1, $p2); - v.gen_abi(&c).unwrap(); - (c, v) + let c: Vyper = compile!($p1); + c.get_abi()? } }; - // returns contract, abi in JSON form, venv - (venv get paris $p1: expr, $p2: expr) => { + // return the ABI as json instead of creating a file + (venv $p1: expr) => { { - let (c, v): (Vyper, Venv) = compile!(venv paris $p1, $p2); - let abi = v.get_abi(&c).unwrap(); - (c, abi, v) - } - }; - - // Generate many ABIs - ($($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many().await.unwrap(); - cs.gen_abi_many().await.unwrap(); - cs + let mut c: Vyper = compile!(venv $p1); + c.get_abi()? } }; // return many ABIs as json - (get $($p1: expr, $p2: expr),+) => { + ($($p1: expr),+) => { { - let mut contracts: Vec = vec![]; + let mut paths: Vec = vec![]; $( - let v = vyper!($p1, $p2); - contracts.push(v); + let v = PathBuf::from($p1); + paths.push(v); )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many().await.unwrap(); - let abis = cs.get_abi_many().await.unwrap(); - (cs, abis) + let cs: Vypers = Vypers::new(paths); + cs.get_abi_many().await? } }; // venv version of many - (venv $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many(&mut cs).await.unwrap(); - venv.gen_abi_many(&cs).await.unwrap(); - (cs, venv) - } - }; - // return many ABIs w/ venv - (venv get $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many(&mut cs).await.unwrap(); - let abi = venv.get_abi_many(&cs).await.unwrap(); - (cs, abi, venv) - } - }; - // gen abis compiled for Paris hard fork - (paris $($p1: expr, $p2: expr),+) => { + (venv $($p1: expr),+) => { { - let mut contracts: Vec = vec![]; + let mut p: Vec = vec![]; $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many_ver(Evm::Paris).await.unwrap(); - cs.gen_abi_many().await.unwrap(); - cs - } - }; - // gen abis compiled for Paris hard fork w/ venv - (venv paris $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many_ver(&mut cs, Evm::Paris).await.unwrap(); - venv.gen_abi_many(&cs).await.unwrap(); - (cs, venv) - } - }; - // return many abis compiled for paris - (get paris $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); - )+ - let mut cs: Vypers = contracts.into(); - cs.compile_many_ver(Evm::Paris).await.unwrap(); - let abi = cs.get_abi_many().await.unwrap(); - (cs, abi) - } - }; - // return many abis compiled for paris w/ venv - (venv get paris $($p1: expr, $p2: expr),+) => { - { - let mut contracts: Vec = vec![]; - $( - let v = vyper!($p1, $p2); - contracts.push(v); + let v = PathBuf::from($p1); + p.push(v); )+ - let mut cs: Vypers = contracts.into(); - let venv: Venv = venv!(); - venv.compile_many_ver(&mut cs, Evm::Paris).await.unwrap(); - let abi = venv.get_abi_many(&cs).await.unwrap(); - (cs, abi, venv) + let mut contracts = Venv::default().init()?.ivyper_venv(None)?.vypers(p); + contracts.get_abi_many().await? } }; } @@ -406,14 +192,12 @@ macro_rules! abi { #[macro_export] macro_rules! venv { () => {{ - Venv::new().init().unwrap().ivyper_venv(None).unwrap() + Venv::default().init()?.ivyper_venv(None)? }}; ($ver: literal) => {{ let version: &str = $ver; Venv::default() - .init() - .unwrap() - .ivyper_venv(Some(version)) - .unwrap() + .init()? + .ivyper_venv(Some(version))? }}; } diff --git a/src/utils.rs b/src/utils.rs index 9d0078a..135a9dc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,16 +1,12 @@ //! Utilities offered by the crate. use std::{ - // error::Error, - env, - fs::{self, read_dir, File, ReadDir}, + fs::read_dir, io::Error, - path::{Path, PathBuf}, - sync::Arc, + path::PathBuf, }; -use anyhow::{bail, Result}; -use tokio::task::JoinHandle; +use crate::vyper_errors::VyperErrors; /// Parses the ERC-5202 bytecode container format for indexing blueprint contracts. /// @@ -21,19 +17,26 @@ use tokio::task::JoinHandle; /// "ERC-5202: Blueprint contract format," Ethereum Improvement Proposals, no. 5202, June 2022. [Online serial]. /// Available: https://eips.ethereum.org/EIPS/eip-5202. -pub fn parse_blueprint(bytecode: &[u8]) -> Result<(u8, Option>, Vec)> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Blueprint { + pub erc_version: u8, + pub preamble_data: Option>, + pub initcode: Vec, +} + +pub fn parse_blueprint(bytecode: &[u8]) -> Result { if bytecode.is_empty() { - bail!("Empty Bytecode"); + Err(VyperErrors::BlueprintError("Empty Bytecode".to_owned()))? } if &bytecode[0..2] != b"\xFE\x71" { - bail!("Not a blueprint!"); + Err(VyperErrors::BlueprintError("Not a blueprint!".to_owned()))? } let erc_version = (&bytecode[2] & 0b11111100) >> 2; let n_length_bytes = &bytecode[2] & 0b11; if n_length_bytes == 0b11 { - bail!("Reserved bits are set"); + Err(VyperErrors::BlueprintError("Reserved bits are set".to_owned()))? } let size_temp = bytecode[3..(3 + n_length_bytes as usize)].to_vec(); @@ -43,7 +46,7 @@ pub fn parse_blueprint(bytecode: &[u8]) -> Result<(u8, Option>, Vec) let size: String = hex::encode(&size_temp); match u32::from_str_radix(&size, size_temp.len() as u32 * 8u32) { Ok(num) => num, - Err(e) => bail!(e), + Err(e) => Err(VyperErrors::IntParseError(e))?, } } }; @@ -60,18 +63,18 @@ pub fn parse_blueprint(bytecode: &[u8]) -> Result<(u8, Option>, Vec) bytecode[3 + n_length_bytes as usize + data_length as usize..].to_vec(); match initcode.is_empty() { true => { - bail!("Empty Initcode!") + Err(VyperErrors::BlueprintError("Empty Initcode!".to_owned()))? } - false => Ok((erc_version, preamble_data, initcode)), + false => Ok(Blueprint{erc_version, preamble_data, initcode}), } } pub async fn scan_workspace(root: PathBuf) -> Result, Error> { let cwd = root.clone(); let h1 = tokio::spawn(async move { get_contracts_in_dir(cwd) }); - let hh_ape = root.join("/contracts"); + let hh_ape = root.join("contracts"); let h2 = tokio::spawn(async move { get_contracts_in_dir(hh_ape) }); - let foundry = root.join("/src"); + let foundry = root.join("src"); let h3 = tokio::spawn(async move { get_contracts_in_dir(foundry) }); let mut res = Vec::new(); for i in [h1, h2, h3].into_iter() { diff --git a/src/venv.rs b/src/venv.rs index 2add131..f9a518b 100644 --- a/src/venv.rs +++ b/src/venv.rs @@ -13,8 +13,10 @@ //! may use the namespace to access methods for use inside the venv. Methods inside the Venv //! namespace are mostly equivalent to the ones in the Vyper module, thus you can rely on the //! documentation for these methods inside the Venv module. -use crate::vyper::{Vyper, Vypers}; -use anyhow::bail; +use crate::{ + vyper::{Vyper, Vypers}, + vyper_errors::VyperErrors, +}; use std::{ path::{Path, PathBuf}, process::Command, @@ -113,7 +115,7 @@ impl<'a> Venv<'a, NotInitialized> { /// Init will check whether or not a venv was created by this program /// If it was not, we will create one - pub fn init(self) -> anyhow::Result> { + pub fn init(self) -> Result, VyperErrors> { match self.venv_path.exists() { true => Ok(Venv { venv_path: self.venv_path, @@ -122,7 +124,9 @@ impl<'a> Venv<'a, NotInitialized> { false => { let a = Command::new("mkdir").arg(self.venv_path).output()?; if !a.status.success() { - bail!("{}", String::from_utf8_lossy(&a.stderr).to_string()); + Err(VyperErrors::DirError( + String::from_utf8_lossy(&a.stderr).to_string(), + ))? } let b = Command::new("python3") @@ -131,7 +135,9 @@ impl<'a> Venv<'a, NotInitialized> { .arg(self.venv_path) .output()?; if !b.status.success() { - bail!("{}", String::from_utf8_lossy(&b.stderr).to_string()); + Err(VyperErrors::VenvError( + String::from_utf8_lossy(&b.stderr).to_string(), + ))? } Ok(Venv { @@ -142,7 +148,7 @@ impl<'a> Venv<'a, NotInitialized> { } } /// For the psychopaths that decide to globally rawdog pip on their PC - fn skip() -> Venv<'a, Skip> { + pub fn skip() -> Venv<'a, Skip> { Venv { venv_path: Path::new("./venv"), state: std::marker::PhantomData::, @@ -152,7 +158,7 @@ impl<'a> Venv<'a, NotInitialized> { impl<'a> Venv<'a, Initialized> { /// Installs vyper into virtual environment /// Optional argument for the version of vyper to be installed - pub fn ivyper_venv(self, ver: Option<&'a str>) -> anyhow::Result> { + pub fn ivyper_venv(self, ver: Option<&'a str>) -> Result, VyperErrors> { match ver { Some(version) => { if cfg!(target_os = "windows") { @@ -161,7 +167,9 @@ impl<'a> Venv<'a, Initialized> { .arg(format!("vyper=={}", version)) .output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::CompilerError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("Version {} of Vyper has been installed", version); } else { @@ -170,7 +178,9 @@ impl<'a> Venv<'a, Initialized> { .arg(format!("vyper=={}", version)) .output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::PipError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("Version {} of Vyper has been installed", version); } @@ -187,7 +197,9 @@ impl<'a> Venv<'a, Initialized> { .arg("vyper") .output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::PipError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("The latest version of vyper has been installed"); } else { @@ -196,7 +208,9 @@ impl<'a> Venv<'a, Initialized> { .arg("vyper") .output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::PipError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("The latest version of vyper has been installed"); } @@ -209,26 +223,26 @@ impl<'a> Venv<'a, Initialized> { } /// Check to see if Vyper is installed in a Venv. If so, transition state to Ready and /// access to the methods of this namespace. - pub fn try_ready(self) -> anyhow::Result> { + pub fn try_ready(self) -> Result, VyperErrors> { if cfg!(target_os = "windows") { - match Path::new("./venv/scripts/vyper").exists() { + match self.venv_path.join("scripts/vyper").exists() { true => Ok(Venv { venv_path: self.venv_path, state: std::marker::PhantomData::, }), - false => { - bail!("Vyper was not installed in venv") - } + false => Err(VyperErrors::CompilerError( + "Vyper was not installed in venv".to_owned(), + ))?, } } else { - match Path::new("./venv/bin/vyper").exists() { + match self.venv_path.join("bin/vyper").exists() { true => Ok(Venv { venv_path: self.venv_path, state: std::marker::PhantomData::, }), - false => { - bail!("Vyper was not installed in venv") - } + false => Err(VyperErrors::CompilerError( + "Vyper was not installed in venv".to_owned(), + ))?, } } } @@ -237,7 +251,7 @@ impl<'a> Venv<'a, Initialized> { impl<'a> Venv<'a, Skip> { /// Installs vyper compiler globally, without the protection of a venv /// Optional argument for the version of vyper to be installed - pub fn ivyper_pip(self, ver: Option<&'a str>) -> anyhow::Result> { + pub fn ivyper_pip(self, ver: Option<&'a str>) -> Result, VyperErrors> { match ver { Some(version) => { let c = Command::new("pip3") @@ -245,14 +259,18 @@ impl<'a> Venv<'a, Skip> { .arg(format!("vyper=={}", version)) .output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::PipError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("Version {} of Vyper has been installed", version); } None => { let c = Command::new("pip3").arg("install").arg("vyper").output()?; if !c.status.success() { - bail!("{}", String::from_utf8_lossy(&c.stderr).to_string()); + Err(VyperErrors::PipError( + String::from_utf8_lossy(&c.stderr).to_string(), + ))? } println!("The Latest Version of Vyper has been installed"); } @@ -269,63 +287,59 @@ impl<'a> Venv<'a, Skip> { } /// Transition to Complete if the Vyper compiler is installed globally - pub fn try_ready(self) -> anyhow::Result> { + pub fn try_ready(self) -> Result, VyperErrors> { match Self::global_exists() { true => Ok(Venv { venv_path: self.venv_path, state: std::marker::PhantomData::, }), - false => { - bail!("Vyper not installed") - } + false => Err(VyperErrors::CompilerError("Vyper not installed".to_owned()))?, } } } impl<'a> Venv<'a, Complete> { - fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> { + pub fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> { Vyper::new(path_to_contract) } - fn vypers(self, paths: Vec) -> Vypers { + pub fn vypers(self, paths: Vec) -> Vypers { Vypers::new(paths) } - fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> { + pub fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> { Vyper::with_abi(path, abi) } - fn vypers_from_dir(self, path: PathBuf) -> Option { + pub fn vypers_from_dir(self, path: PathBuf) -> Option { Vypers::in_dir(path) } - async fn vypers_from_workspace(self, path: PathBuf) -> Option { + pub async fn vypers_from_workspace(self, path: PathBuf) -> Option { Vypers::in_workspace(path).await } } impl<'a> Venv<'a, Ready> { - fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> { + pub fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> { Vyper::with_venv(path_to_contract, self.venv_path) } - fn vypers(self, paths: Vec) -> Vypers { + pub fn vypers(self, paths: Vec) -> Vypers { Vypers::with_venv(paths, self.venv_path) } - fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> { + pub fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> { Vyper::with_venv_and_abi(path, self.venv_path, abi) } - fn vypers_from_dir(self, path: PathBuf) -> Option { + pub fn vypers_from_dir(self, path: PathBuf) -> Option { let vyps = Vypers::in_dir(path); - let ret = vyps.map(|e| e.set_venv(self.venv_path.to_path_buf())); - ret + vyps.map(|e| e.set_venv(self.venv_path.to_path_buf())) } - async fn vypers_from_workspace(self, path: PathBuf) -> Option { + pub async fn vypers_from_workspace(self, path: PathBuf) -> Option { let vyps = Vypers::in_workspace(path).await; - let ret = vyps.map(|e| e.set_venv(self.venv_path.to_path_buf())); - ret + vyps.map(|e| e.set_venv(self.venv_path.to_path_buf())) } } diff --git a/src/vyper.rs b/src/vyper.rs index 2c54276..cec70d7 100644 --- a/src/vyper.rs +++ b/src/vyper.rs @@ -2,13 +2,12 @@ use crate::{ utils::{self, get_contracts_in_dir}, - vyper_errors::CompilerError, + vyper_errors::VyperErrors, }; -use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; use serde_json::{to_writer_pretty, Value}; use std::{ - error::Error, + borrow::BorrowMut, fmt::Display, fs::File, io::{BufWriter, Write}, @@ -17,6 +16,7 @@ use std::{ sync::Arc, thread, }; +use tokio::task::JoinHandle; /// Represents important information about a Vyper contract. ABI doesn't need to point to an /// existing file since it can just be generated using `gen_abi()`. If the ABI already exists at the given path, you can use serde_json to retrieve it from a file. @@ -41,12 +41,11 @@ impl<'a> Display for Vyper<'a> { impl<'a> Vyper<'a> { /// Constructor function that takes in the path to your vyper contract and the _desired path/{name}.json_ for your ABI pub fn new(path: &'a Path) -> Self { - let abi = path.with_extension(".json"); - + let np = path.with_extension("json"); Self { path_to_code: path, bytecode: None, - abi, + abi: np, venv: None, } } @@ -61,7 +60,7 @@ impl<'a> Vyper<'a> { } pub fn with_venv(path: &'a Path, venv: &'a Path) -> Vyper<'a> { - let abi = path.with_extension(".json"); + let abi = path.with_extension("json"); Vyper { path_to_code: path, @@ -80,12 +79,24 @@ impl<'a> Vyper<'a> { } } + pub fn abi_mut(&mut self) -> &mut PathBuf { + self.abi.borrow_mut() + } + + pub fn abi_exists(&self) -> bool { + self.abi.exists() + } + + pub fn contract_exists(&self) -> bool { + self.path_to_code.exists() + } + pub fn get_vyper(&self) -> String { if let Some(venv) = self.venv { if cfg!(target_os = "windows") { - format!("{}/scripts/vyper", venv.to_string_lossy().to_string()) + format!("{}/scripts/vyper", venv.to_string_lossy()) } else { - format!("{}/bin/vyper", venv.to_string_lossy().to_string()) + format!("{}/bin/vyper", venv.to_string_lossy()) } } else { "vyper".to_owned() @@ -95,9 +106,9 @@ impl<'a> Vyper<'a> { pub fn get_pip(&self) -> String { if let Some(venv) = self.venv { if cfg!(target_os = "windows") { - format!("{}/scripts/pip3", venv.to_string_lossy().to_string()) + format!("{}/scripts/pip3", venv.to_string_lossy()) } else { - format!("{}/bin/pip3", venv.to_string_lossy().to_string()) + format!("{}/bin/pip3", venv.to_string_lossy()) } } else { "pip3".to_owned() @@ -109,20 +120,20 @@ impl<'a> Vyper<'a> { } /// check the version of the vyper compiler - pub fn get_version(&self) -> Result> { + pub fn get_version(&self) -> Result { let out = Command::new(self.get_vyper()).arg("--version").output()?; if !out.status.success() { - return Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( "Couldn't locate version info, installation does not exist".to_string(), - ))); + ))? } Ok(String::from_utf8_lossy(&out.stdout).to_string()) } /// Compiles a vyper contract by invoking the vyper compiler, updates the ABI field in the Vyper struct - pub fn compile(&mut self) -> Result<(), Box> { + pub fn compile(&mut self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) - .arg(&self.path_to_code) + .arg(self.path_to_code) .output()?; if compiler_output.status.success() { let mut out = String::from_utf8_lossy(&compiler_output.stdout).to_string(); @@ -132,33 +143,33 @@ impl<'a> Vyper<'a> { self.bytecode = Some(out); Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } - pub fn compile_blueprint(&mut self) -> Result<(), Box> { + pub fn compile_blueprint(&mut self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("blueprint_bytecode") - .arg(&self.path_to_code) + .arg(self.path_to_code) .output()?; if compiler_output.status.success() { let out = String::from_utf8_lossy(&compiler_output.stdout).to_string(); self.bytecode = Some(out); Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Compiles a vyper contract by invoking the vyper compiler, arg for specifying the EVM version to compile to - pub fn compile_ver(&mut self, ver: &Evm) -> Result<(), Box> { + pub fn compile_ver(&mut self, ver: &Evm) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) - .arg(&self.path_to_code) + .arg(self.path_to_code) .arg("--evm-version") .arg(ver.to_string()) .output()?; @@ -172,17 +183,17 @@ impl<'a> Vyper<'a> { Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Generates the ABI and creates a file @ the abi path specified in the Vyper struct - pub fn gen_abi(&self) -> Result<(), Box> { + pub fn gen_abi(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("abi") - .arg(&self.abi) + .arg(&self.path_to_code) .output()?; if compiler_output.status.success() { @@ -190,25 +201,23 @@ impl<'a> Vyper<'a> { &compiler_output.stdout, ))?; - let abi_path = self.path_to_code.with_extension(".json"); - - let file = File::create(abi_path)?; + let file = File::create(&self.abi)?; to_writer_pretty(file, &json)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Generates the ABI and creates a file @ the abi path specified in the Vyper struct - pub fn get_abi(&self) -> Result> { + pub fn get_abi(&self) -> Result { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("abi") - .arg(&self.abi) + .arg(&self.path_to_code) .output()?; if compiler_output.status.success() { @@ -217,14 +226,14 @@ impl<'a> Vyper<'a> { ))?; Ok(json) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Storage layout as JSON, saves it to a file - pub fn storage_layout(&self) -> Result<(), Box> { + pub fn storage_layout(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("layout") @@ -239,13 +248,13 @@ impl<'a> Vyper<'a> { to_writer_pretty(file, &json)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// AST of your contract as JSON, saves it to a file - pub fn ast(&self) -> Result<(), Box> { + pub fn ast(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("ast") @@ -260,13 +269,13 @@ impl<'a> Vyper<'a> { to_writer_pretty(file, &json)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Generates an external interface for your vyper contract to be called with - pub fn interface(&self) -> Result<(), Box> { + pub fn interface(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("external_interface") @@ -277,13 +286,13 @@ impl<'a> Vyper<'a> { buffer.write_all(&compiler_output.stdout)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Generates the opcodes produced by your vyper contract, saves it as a text file - pub fn opcodes(&self) -> Result<(), Box> { + pub fn opcodes(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("opcodes") @@ -295,13 +304,13 @@ impl<'a> Vyper<'a> { buffer.write_all(&compiler_output.stdout)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Generates the opcodes produced by your vyper contract at runtime, saves it as a text file - pub fn opcodes_runtime(&self) -> Result<(), Box> { + pub fn opcodes_runtime(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("opcodes_runtime") @@ -313,13 +322,13 @@ impl<'a> Vyper<'a> { buffer.write_all(&compiler_output.stdout)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Natspec user documentation for vyper contract - pub fn userdoc(&self) -> Result<(), Box> { + pub fn userdoc(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("userdoc") @@ -330,13 +339,13 @@ impl<'a> Vyper<'a> { buffer.write_all(&compiler_output.stdout)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } /// Natspec dev documentation for vyper contract - pub fn devdoc(&self) -> Result<(), Box> { + pub fn devdoc(&self) -> Result<(), VyperErrors> { let compiler_output = Command::new(self.get_vyper()) .arg("-f") .arg("devdoc") @@ -347,9 +356,9 @@ impl<'a> Vyper<'a> { buffer.write_all(&compiler_output.stdout)?; Ok(()) } else { - Err(Box::new(CompilerError::new( + Err(VyperErrors::CompilerError( String::from_utf8_lossy(&compiler_output.stderr).to_string(), - )))? + ))? } } } @@ -360,12 +369,10 @@ impl<'a> Vyper<'a> { pub struct VyperStack<'a>(pub &'a mut [Vyper<'a>]); impl<'a> VyperStack<'a> { - pub fn compile_many( - &mut self, - ) -> Result<(), Box> { + pub fn compile_many(&mut self) -> Result<(), VyperErrors> { thread::scope(|s| { for i in self.0.iter_mut() { - s.spawn(|| -> Result<(), Box> { + s.spawn(|| -> Result<(), VyperErrors> { i.compile()?; Ok(()) }); @@ -375,14 +382,11 @@ impl<'a> VyperStack<'a> { Ok(()) } - pub fn compile_many_ver( - &mut self, - evm_version: &Evm, - ) -> Result<(), Box> { + pub fn compile_many_ver(&mut self, evm_version: &Evm) -> Result<(), VyperErrors> { thread::scope(|s| { for i in self.0.iter_mut() { - s.spawn(|| -> Result<(), Box> { - i.compile_ver(&evm_version)?; + s.spawn(|| -> Result<(), VyperErrors> { + i.compile_ver(evm_version)?; Ok(()) }); } @@ -391,10 +395,10 @@ impl<'a> VyperStack<'a> { Ok(()) } - pub fn gen_abi_many(&self) -> Result<(), Box> { + pub fn gen_abi_many(&self) -> Result<(), VyperErrors> { thread::scope(|s| { for i in self.0.iter() { - s.spawn(|| -> Result<(), Box> { + s.spawn(|| -> Result<(), VyperErrors> { i.gen_abi()?; Ok(()) }); @@ -436,12 +440,10 @@ impl Vypers { } pub fn new(paths: Vec) -> Self { - let abis = paths.iter().map(|e| e.with_extension(".json")).collect(); - Self { - path_to_code: paths, + path_to_code: paths.clone(), bytecode: None, - abi: abis, + abi: paths.iter().map(|e| e.with_extension("json")).collect(), venv: None, } } @@ -463,7 +465,7 @@ impl Vypers { } pub fn with_venv(paths: Vec, venv: &Path) -> Self { - let abis = paths.iter().map(|e| e.with_extension(".json")).collect(); + let abis = paths.iter().map(|e| e.with_extension("json")).collect(); Self { path_to_code: paths, @@ -480,9 +482,9 @@ impl Vypers { pub fn get_vyper(&self) -> String { if let Some(venv) = &self.venv { if cfg!(target_os = "windows") { - format!("{}/scripts/vyper", venv.to_string_lossy().to_string()) + format!("{}/scripts/vyper", venv.to_string_lossy()) } else { - format!("{}/bin/vyper", venv.to_string_lossy().to_string()) + format!("{}/bin/vyper", venv.to_string_lossy()) } } else { "vyper".to_owned() @@ -492,9 +494,9 @@ impl Vypers { pub fn get_pip(&self) -> String { if let Some(venv) = &self.venv { if cfg!(target_os = "windows") { - format!("{}/scripts/pip3", venv.to_string_lossy().to_string()) + format!("{}/scripts/pip3", venv.to_string_lossy()) } else { - format!("{}/bin/pip3", venv.to_string_lossy().to_string()) + format!("{}/bin/pip3", venv.to_string_lossy()) } } else { "pip3".to_owned() @@ -502,10 +504,10 @@ impl Vypers { } /// Compile multiple vyper contracts concurrently on new threads, updates the ABI field in Vypers - pub async fn compile_many(&mut self) -> Result<(), Box> { + pub async fn compile_many(&mut self) -> Result<(), VyperErrors> { let path = Arc::new(self.path_to_code.clone()); let mut out_vec: Vec = Vec::with_capacity(self.path_to_code.len()); - let mut threads = vec![]; + let mut threads: Vec>> = vec![]; let vy: Arc = Arc::new(self.get_vyper()); for i in 0..self.path_to_code.len() { let paths = Arc::clone(&path); @@ -521,13 +523,15 @@ impl Vypers { } Ok(out) } else { - bail!(String::from_utf8_lossy(&compiler_output.stderr).to_string()) + Err(VyperErrors::CompilerError( + String::from_utf8_lossy(&compiler_output.stderr).to_string(), + ))? } }); threads.push(cthread); } for child_thread in threads { - let x = child_thread.await.unwrap()?; + let x = child_thread.await??; out_vec.push(x); } self.bytecode = Some(out_vec); @@ -538,12 +542,12 @@ impl Vypers { pub async fn compile_many_ver( &mut self, ver: Evm, - ) -> Result<(), Box> { + ) -> Result<(), VyperErrors> { let path = Arc::new(self.path_to_code.clone()); let vy = Arc::new(self.get_vyper()); let mut out_vec: Vec = Vec::with_capacity(self.path_to_code.len()); let version = ver.to_string(); - let mut threads = vec![]; + let mut threads: Vec>> = vec![]; for i in 0..self.path_to_code.len() { let paths = Arc::clone(&path); let bin = Arc::clone(&vy); @@ -562,13 +566,15 @@ impl Vypers { } Ok(out) } else { - bail!(String::from_utf8_lossy(&compiler_output.stderr).to_string()) + Err(VyperErrors::CompilerError( + String::from_utf8_lossy(&compiler_output.stderr).to_string(), + ))? } }); threads.push(cthread); } for child_thread in threads { - let x = child_thread.await.unwrap()?; + let x = child_thread.await??; out_vec.push(x); } self.bytecode = Some(out_vec); @@ -576,11 +582,11 @@ impl Vypers { } /// Generates ABIs for each vyper contract concurrently - pub async fn gen_abi_many(&mut self) -> Result<(), Box> { + pub async fn gen_abi_many(&mut self) -> Result<(), VyperErrors> { let abi_path = Arc::new(self.abi.clone()); let vy = Arc::new(self.get_vyper()); let c_path = Arc::new(self.path_to_code.clone()); - let mut threads = vec![]; + let mut threads: Vec>> = vec![]; for i in 0..c_path.len() { let c = Arc::clone(&c_path); let abi = Arc::clone(&abi_path); @@ -598,21 +604,21 @@ impl Vypers { let file = File::create(&abi[i])?; to_writer_pretty(file, &json)?; } else { - bail!(String::from_utf8_lossy(&compiler_output.stderr).to_string()) + Err(VyperErrors::CompilerError(String::from_utf8_lossy(&compiler_output.stderr).to_string()))? } Ok(()) }); threads.push(cthread); } for child_thread in threads { - child_thread.await.unwrap()? + child_thread.await?? } Ok(()) } - pub async fn get_abi_many(&self) -> Result, Box> { + pub async fn get_abi_many(&self) -> Result, VyperErrors> { let c_path = Arc::new(self.path_to_code.clone()); - let mut threads = vec![]; + let mut threads: Vec>> = vec![]; let vy = Arc::new(self.get_vyper()); for i in 0..self.path_to_code.len() { let c = Arc::clone(&c_path); @@ -629,7 +635,7 @@ impl Vypers { ))?; Ok(json) } else { - bail!(String::from_utf8_lossy(&compiler_output.stderr).to_string()) + Err(VyperErrors::CompilerError(String::from_utf8_lossy(&compiler_output.stderr).to_string()))? } }); threads.push(cthread); diff --git a/src/vyper_errors.rs b/src/vyper_errors.rs index 7f807a5..cc4977f 100644 --- a/src/vyper_errors.rs +++ b/src/vyper_errors.rs @@ -1,22 +1,58 @@ //! This module contains the main error type returned when there's some issue with the compiler in //! the Vyper module. -use std::{error::Error, fmt::Display}; +use std::{error::Error, fmt::Display, io, num::ParseIntError}; #[derive(Debug)] -pub struct CompilerError { - pub source: String, +pub enum VyperErrors { + IoError(io::Error), + CompilerError(String), + SerializationError(serde_json::Error), + ConcurrencyError(tokio::task::JoinError), + PipError(String), + DirError(String), + VenvError(String), + BlueprintError(String), + IntParseError(ParseIntError), } -impl CompilerError { - pub(crate) fn new(reason: String) -> Self { - Self { source: reason } +impl Display for VyperErrors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VyperErrors::IoError(err) => { + write!(f, "An error occured while using system IO: {}", err) + }, + VyperErrors::SerializationError(s) => write!( + f, + "An error occurred while serializing or deserializing data: {}", + s, + ), + VyperErrors::CompilerError(msg) => write!(f, "{}", msg), + VyperErrors::PipError(msg) => write!(f, "{}", msg), + VyperErrors::ConcurrencyError(je) => write!(f, "Failed to join async tasks: {}", je), + VyperErrors::DirError(msg) => write!(f, "{}", msg), + VyperErrors::VenvError(msg) => write!(f, "{}", msg), + VyperErrors::BlueprintError(msg) => write!(f, "{}", msg), + VyperErrors::IntParseError(e) => write!(f, "{}", e), + } } } -impl Display for CompilerError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Failed to compile Vyper contract") +impl Error for VyperErrors {} + +impl From for VyperErrors { + fn from(value: std::io::Error) -> Self { + VyperErrors::IoError(value) + } +} + +impl From for VyperErrors { + fn from(value: serde_json::Error) -> Self { + VyperErrors::SerializationError(value) } } -impl Error for CompilerError {} +impl From for VyperErrors { + fn from(value: tokio::task::JoinError) -> Self { + VyperErrors::ConcurrencyError(value) + } +} diff --git a/~/.config/nvim-data/undodir/%Users%crypdoughdoteth%dev%active%vyper-rs%Cargo.toml b/~/.config/nvim-data/undodir/%Users%crypdoughdoteth%dev%active%vyper-rs%Cargo.toml index 878d6fe..1a37ae9 100644 Binary files a/~/.config/nvim-data/undodir/%Users%crypdoughdoteth%dev%active%vyper-rs%Cargo.toml and b/~/.config/nvim-data/undodir/%Users%crypdoughdoteth%dev%active%vyper-rs%Cargo.toml differ