diff --git a/contracts/examples/multisig/interact-rs/.gitignore b/contracts/examples/multisig/interact-rs/.gitignore index ea1b920080..0d3b55f264 100644 --- a/contracts/examples/multisig/interact-rs/.gitignore +++ b/contracts/examples/multisig/interact-rs/.gitignore @@ -5,4 +5,4 @@ state.toml # Trace file of interactor tooling -interactor_trace.scen.json +interactor*.scen.json diff --git a/contracts/examples/multisig/interact-rs/src/multisig_interact.rs b/contracts/examples/multisig/interact-rs/src/multisig_interact.rs index 289ac3ade2..f5e79795f0 100644 --- a/contracts/examples/multisig/interact-rs/src/multisig_interact.rs +++ b/contracts/examples/multisig/interact-rs/src/multisig_interact.rs @@ -58,9 +58,17 @@ async fn main() { Some(multisig_interact_cli::InteractCliCommand::MultiDeploy(args)) => { multisig_interact.multi_deploy(&args.count).await; }, + Some(multisig_interact_cli::InteractCliCommand::NftFullAllRoles) => { + multisig_interact + .issue_multisig_and_collection_with_all_roles_full() + .await; + }, Some(multisig_interact_cli::InteractCliCommand::NftFull) => { multisig_interact.issue_multisig_and_collection_full().await; }, + Some(multisig_interact_cli::InteractCliCommand::NftIssueAllRoles) => { + multisig_interact.issue_collection_with_all_roles().await; + }, Some(multisig_interact_cli::InteractCliCommand::NftIssue) => { multisig_interact.issue_collection().await; }, diff --git a/contracts/examples/multisig/interact-rs/src/multisig_interact_cli.rs b/contracts/examples/multisig/interact-rs/src/multisig_interact_cli.rs index e2a67a199a..49c7f21d82 100644 --- a/contracts/examples/multisig/interact-rs/src/multisig_interact_cli.rs +++ b/contracts/examples/multisig/interact-rs/src/multisig_interact_cli.rs @@ -22,8 +22,18 @@ pub enum InteractCliCommand { Feed, #[command(name = "multi-deploy", about = "Multiple deploy contracts")] MultiDeploy(MultiDeployArgs), + #[command( + name = "nft-full-all-roles", + about = "Issue multisig and collection with all roles" + )] + NftFullAllRoles, #[command(name = "nft-full", about = "Issue multisig and collection")] NftFull, + #[command( + name = "nft-issue-all-roles", + about = "Issue collection with all roles" + )] + NftIssueAllRoles, #[command(name = "nft-issue", about = "Issue collection")] NftIssue, #[command(name = "nft-items", about = "Create items")] diff --git a/contracts/examples/multisig/interact-rs/src/multisig_interact_nfts.rs b/contracts/examples/multisig/interact-rs/src/multisig_interact_nfts.rs index df7ab0c1ad..ebb6c4f85f 100644 --- a/contracts/examples/multisig/interact-rs/src/multisig_interact_nfts.rs +++ b/contracts/examples/multisig/interact-rs/src/multisig_interact_nfts.rs @@ -8,6 +8,7 @@ const ISSUE_COST: u64 = 50000000000000000; // 0.05 EGLD const COLLECTION_NAME: &str = "TestCollection1"; const COLLECTION_TICKER: &str = "TESTCOLL1"; +const TOKEN_TYPE: &str = "NFT"; const NUM_ITEMS: usize = 3; const ROYALTIES: usize = 3000; @@ -23,6 +24,94 @@ impl MultisigInteract { self.create_items().await; } + pub async fn issue_multisig_and_collection_with_all_roles_full(&mut self) { + self.deploy().await; + self.feed_contract_egld().await; + self.issue_collection_with_all_roles().await; + self.interactor.sleep(Duration::from_secs(15)).await; + self.create_items().await; + } + + pub async fn propose_issue_collection_with_all_roles(&mut self) -> Option { + let system_sc_address = bech32::decode(SYSTEM_SC_BECH32); + let mut typed_sc_call = self + .state + .multisig() + .propose_async_call( + system_sc_address, + ISSUE_COST, + "registerAndSetAllRoles".to_string(), + MultiValueVec::from([ + COLLECTION_NAME.as_bytes(), + COLLECTION_TICKER.as_bytes(), + TOKEN_TYPE.as_bytes(), + top_encode_to_vec_u8_or_panic(&0u32).as_slice(), + ]), + ) + .into_blockchain_call() + .from(&self.wallet_address) + .gas_limit("10,000,000") + .expect(TxExpect::ok()); + + self.interactor.sc_call(&mut typed_sc_call).await; + + let result = typed_sc_call.result(); + if result.is_err() { + println!( + "propose issue collection with roles failed with: {}", + result.err().unwrap() + ); + return None; + } + + let action_id = result.unwrap(); + println!("successfully proposed issue colllection with roles action `{action_id}`"); + Some(action_id) + } + + pub async fn issue_collection_with_all_roles(&mut self) { + println!("proposing issue collection with all roles..."); + let action_id = self.propose_issue_collection_with_all_roles().await; + if action_id.is_none() { + return; + } + + let action_id = action_id.unwrap(); + println!("perfoming issue collection with all roles action `{action_id}`..."); + + if !self.quorum_reached(action_id).await && !self.sign(action_id).await { + return; + } + println!("quorum reached for action `{action_id}`"); + + let mut typed_sc_call = self + .state + .multisig() + .perform_action_endpoint(action_id) + .into_blockchain_call() + .from(&self.wallet_address) + .gas_limit("80,000,000"); + + self.interactor.sc_call(&mut typed_sc_call).await; + + let result = typed_sc_call + .response() + .issue_non_fungible_new_token_identifier(); + if result.is_err() { + println!( + "perform issue collection with all roles failed with: {}", + result.err().unwrap() + ); + return; + } + + self.collection_token_identifier = result.unwrap(); + println!( + "collection token identifier: {}", + self.collection_token_identifier + ); + } + pub async fn propose_issue_collection(&mut self) -> Option { let system_sc_address = bech32::decode(SYSTEM_SC_BECH32); let mut typed_sc_call = self diff --git a/contracts/examples/multisig/scenarios/interactor_nft_all_roles.scen.json b/contracts/examples/multisig/scenarios/interactor_nft_all_roles.scen.json new file mode 100644 index 0000000000..8746f7fba9 --- /dev/null +++ b/contracts/examples/multisig/scenarios/interactor_nft_all_roles.scen.json @@ -0,0 +1,526 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60": { + "nonce": "619", + "balance": "101110120254850000003", + "esdt": { + "str:CAN-14dc0a": "1000", + "str:CAN-2abf4b": "1000", + "str:CAN-6d39e6": "1000", + "str:CAN-ac1592": "1000" + }, + "username": "" + } + } + }, + { + "step": "setState", + "accounts": { + "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba": { + "nonce": "251", + "balance": "101558004165010000000", + "esdt": { + "str:CAMP-3bd1c7": { + "instances": [ + { + "nonce": "26", + "balance": "1" + }, + { + "nonce": "23", + "balance": "1" + }, + { + "nonce": "21", + "balance": "1" + }, + { + "nonce": "25", + "balance": "1" + }, + { + "nonce": "24", + "balance": "1" + }, + { + "nonce": "22", + "balance": "1" + } + ] + }, + "str:TEST-0f54a2": { + "instances": [ + { + "nonce": "9", + "balance": "1" + }, + { + "nonce": "1", + "balance": "1" + }, + { + "nonce": "2", + "balance": "1" + }, + { + "nonce": "6", + "balance": "1" + } + ] + }, + "str:TEST-48ef66": { + "instances": [ + { + "nonce": "5", + "balance": "1" + }, + { + "nonce": "4", + "balance": "1" + } + ] + }, + "str:TEST-d2b50f": { + "instances": [ + { + "nonce": "1", + "balance": "2" + } + ] + }, + "str:TEST-fb415a": { + "instances": [ + { + "nonce": "3", + "balance": "1" + }, + { + "nonce": "2", + "balance": "1" + }, + { + "nonce": "4", + "balance": "1" + } + ] + } + }, + "username": "" + } + } + }, + { + "step": "setState", + "accounts": { + "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17": { + "nonce": "222", + "balance": "1767500200900000000", + "username": "" + } + } + }, + { + "step": "setState", + "accounts": { + "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033": { + "nonce": "434", + "balance": "62227641093810000000", + "esdt": { + "str:USDC-091bd3": "9997000000000", + "str:XRF-079f0d": "999999805000000000000000000", + "str:XUSDC-929b9b": "1000000000000000000000000" + }, + "username": "" + } + } + }, + { + "step": "setState", + "accounts": { + "0x00000000000000000500c114ee7698050a4d40c092add8c31d25e99a6e1ec2ee": { + "nonce": "0", + "balance": "175064792195269569513", + "esdt": { + "str:WEGLD-6cf38e": { + "instances": [], + "roles": [ + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" + ] + } + }, + "username": "", + "storage": { + "0x7772617070656445676c64546f6b656e4964": "0x5745474c442d366366333865" + }, + "code": "0x0061736d0100000001661160000060017f0060027f7f017f60027f7f006000017f60017f017f60037f7f7f0060037f7f7f017f60057f7f7e7f7f017f60047f7f7f7f0060067e7f7f7f7f7f017f60047f7f7f7f017f60027f7e0060017e006000017e60057f7f7f7f7f0060037e7f7f0002cc062303656e760b7369676e616c4572726f72000303656e7618626967496e7447657445787465726e616c42616c616e6365000303656e760a6d4275666665724e6577000403656e760d6d427566666572417070656e64000203656e76096d4275666665724571000203656e76106d616e61676564534341646472657373000103656e761b6d616e61676564457865637574654f6e44657374436f6e74657874000a03656e760f636c65616e52657475726e44617461000003656e760d6d616e6167656443616c6c6572000103656e76136d616e616765644f776e657241646472657373000103656e76126d427566666572476574417267756d656e74000203656e760f6765744e756d417267756d656e7473000403656e76126d427566666572417070656e644279746573000703656e760f6d4275666665725365744279746573000703656e76106d4275666665724765744c656e677468000503656e76196d42756666657246726f6d426967496e74556e7369676e6564000203656e76136d42756666657247657442797465536c696365000b03656e76126d42756666657253746f726167654c6f6164000203656e76126d616e616765645369676e616c4572726f72000103656e760e626967496e74536574496e743634000c03656e760a626967496e745369676e000503656e76136d42756666657253746f7261676553746f7265000203656e760e636865636b4e6f5061796d656e74000003656e7614626967496e7446696e697368556e7369676e6564000103656e760d6d42756666657246696e697368000503656e7614736d616c6c496e7446696e6973685369676e6564000d03656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000103656e7609626967496e74436d70000203656e760a6765744761734c656674000e03656e761b6d616e616765645472616e7366657256616c756545786563757465000803656e76136765744e756d455344545472616e7366657273000403656e7612626967496e7447657443616c6c56616c7565000103656e7609626967496e74416464000603656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465000803656e760f6d42756666657247657442797465730002032c2b0f00040405020310010400010303040503020301050509030306060900040501000000000000000000000005030100110619037f01418080c0000b7f0041e5d1c0000b7f0041f0d1c0000b079b010c066d656d6f7279020004696e69740044146765744c6f636b656445676c6442616c616e63650045156765745772617070656445676c64546f6b656e496400460869735061757365640047057061757365004807756e706175736500490a756e7772617045676c64004a087772617045676c64004b0863616c6c4261636b004c0a5f5f646174615f656e6403010b5f5f686561705f6261736503020abc162b2e000240200120024d0440200220044d0d011024000b1024000b2000200220016b3602042000200120036a3602000b05001043000b2301027f10262200100520001026210041c5d1c00010221a41c5d1c0002000100120000b1b01017f41a483c00041a483c00028020041016b220036020020000b0f01017f10022201200010031a20010b0b0020002001100441004a0b0900200020011000000b1f01017f4167100510262203102b20004167200320012002102610061a10070b08002000420010130b0c01017f10262200100820000b1e01017f1026220010092000102c102804400f0b41f082c00041241000000b1500100b20004604400f0b41cb81c00041191000000b4701017f230041106b2202240020022001410874418080fc077120014118747220014108764180fe03712001411876727236020c20002002410c6a4104100c1a200241106a24000b0d0010311a200020011032102f0b1401017f1026220041d482c0004100100d1a20000b0f01017f102622012000100f1a20010b0d0010311a200020011027102f0b1101017f1026220220002001100d1a20020b09002000200110031a0b5501017f20002d00042101200041003a000402402001410171044041a883c00028020022014191ce004f0d01200028020041ac83c0002001100c1a41a883c000410036020041bcd1c00041003a00000b0f0b1024000bae0102027f017e230041106b2202240020024200370308200010382200100e220141094904402002200241086a41082001103920004100200228020422002002280200220110101a027f41002000450d001a034020000440200041016b210020013100002003420886842103200141016a21010c010b0b02402003420158044041002003a741016b0d021a0c010b41f281c0004112103a000b41010b200241106a24000f0b41e481c000410e103a000b0d0020001026220010111a20000b3b01017f230041106b22042400200441086a41002003200120021023200428020c21012000200428020836020020002001360204200441106a24000b1b01017f418482c00041161034220220002001100c1a20021012000bf20101047f230041106b2203240020032000100e22024118742002410874418080fc07717220024108764180fe03712002411876727236020c20012003410c6a4104103c20012d00042102200141003a00040240024002402002410171220204402000100e22054190ce0041a883c00028020022046b4b0d0220032004200420056a2204103d200041002003280204200328020010101a41a883c00020043602000c010b2001280200200010350b200120023a00040c010b2001103620012802002000103520012d0004200120023a0004410171450d0041a883c000410036020041bcd1c00041003a00000b200341106a24000b800101027f230041106b220324000240024020002d000404404190ce0041a883c00028020022046b2002490d01200341086a2004200220046a2200103d2003280208200328020c20012002103e41a883c00020003602000c020b200028020020012002100c1a0c010b20001036200028020020012002100c1a0b200341106a24000b4001017f230041106b22032400200341086a2001200241ac83c0004190ce001023200328020c21012000200328020836020020002001360204200341106a24000bb00201067f2001200346044020012203410f4b04402000410020006b41037122056a210420050440200221010340200020012d00003a0000200141016a2101200041016a22002004490d000b0b2004200320056b2203417c7122066a21000240200220056a220541037122010440200641004c0d012005417c71220741046a21024100200141037422086b4118712109200728020021010340200420012008762002280200220120097472360200200241046a2102200441046a22042000490d000b0c010b200641004c0d0020052102034020042002280200360200200241046a2102200441046a22042000490d000b0b20034103712103200520066a21020b20030440200020036a21010340200020022d00003a0000200241016a2102200041016a22002001490d000b0b0f0b1043000b1c0041be82c0004113103410374504400f0b419a82c00041121029000b0b0041ac82c000411210340b09002000101441004a0ba60101037f230041106b2201240041be82c00041131034200142808080808080808001420020001b3703080240200045044041d482c00021000c010b4100210003400240024020004108470440200141086a20006a2d00002202450d022002411874411f7520006a220041094f0d01410820006b21022000200141086a6a21000c040b1043000b104d000b200041016a21000c000b000b20002002103410151a200141106a24000b0500104d000b1a01017f10164101102e410010262200100a1a1040200010151a0b0c0010164100102e102510170b0f0010164100102e1040103810181a0b160010164100102e41be82c000411310341037ad10190b0e001016102d4100102e410110420b0e001016102d4100102e410010420bed0302097f017e230041106b220124004100102e103f416b2102024041c4d1c0002d000022000440416b41ffffffff0720001b21020c010b41c4d1c00041013a0000416b101a0b02402002100e4170714110460440410021002002100e2106200141086a2107410121050340200041106a220420064b0d022007420037030020014200370300200220004110200110101a2005044020012902042209423886200942288642808080808080c0ff0083842009421886428080808080e03f8320094208864280808080f01f838484200942088842808080f80f832009421888428080fc07838420094228884280fe038320094238888484842109200128020022004118742000410874418080fc07717220004108764180fe0371200041187672722108200128020c22004118742000410874418080fc07717220004108764180fe037120004118767272210341002105200421000c010b0b1043000b418481c00041221000000b024002400240200950044020081040103822041028450d0120031041450d0220031025101b41004a0d031031220020041033200020031030101c41ea80c000410d10342000102a102c2003420010311031101d1a200141106a24000f0b41d482c000411c1000000b418080c00041101029000b419080c000411c1029000b41ac80c00041231029000beb0301097f230041206b220124000240101e4504404100102e103f41752103024041c0d1c0002d000022000440417541ffffffff0720001b21030c010b41c0d1c00041013a00004175101f0b20031041450d011040103821041031220020041033200020031030101c41f780c000410d10342000102a102c10312107103121081031210520041027210210262200102b20002000200310202001420037020c20012002410874418080fc077120024118747220024108764180fe03712002411876727236020820012000410874418080fc077120004118747220004108764180fe0371200041187672723602142005200141086a4110100c1a200542002007200810211a2001027f41bcd1c0002d0000220045044041bcd1c00041013a000041a883c0004100360200200141ac83c0004190ce00410010392001280200200128020441d482c0004100103e10310c010b41d482c000410010340b360218200120004101733a001c2004200141186a2200103b200142003703082000200141086a22024108103c200310322000103b20012802182100200120012d001c3a000c2001200036020820021036200128020820012d000c044041a883c000410036020041bcd1c00041003a00000b10181a200141206a24000f0b41a681c00041251000000b41cf80c000411b1029000b0300010b0c00419483c000410e1000000b0bb8030200418080c0000ba20357726f6e67206573647420746f6b656e4d75737420706179206d6f7265207468616e203020746f6b656e7321436f6e747261637420646f6573206e6f74206861766520656e6f7567682066756e64735061796d656e74206d757374206265206d6f7265207468616e2030455344544c6f63616c4275726e455344544c6f63616c4d696e74696e636f7272656374206e756d626572206f662045534454207472616e736665727366756e6374696f6e20646f6573206e6f74206163636570742045534454207061796d656e7477726f6e67206e756d626572206f6620617267756d656e7473696e70757420746f6f206c6f6e67696e707574206f7574206f662072616e676573746f72616765206465636f6465206572726f723a20436f6e7472616374206973207061757365647772617070656445676c64546f6b656e496470617573655f6d6f64756c653a70617573656400000066756e6769626c65204553445420746f6b656e206578706563746564456e64706f696e742063616e206f6e6c792062652063616c6c6564206279206f776e657270616e6963206f636375727265640041a483c0000b049cffffff" + } + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "creatorNonce": "619", + "newAddress": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "contractCode": "file:../output/multisig.wasm", + "arguments": [ + "0x02", + "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", + "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17", + "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033" + ], + "gasLimit": "70,000,000", + "gasPrice": "" + }, + "expect": { + "status": "0" + } + }, + { + "step": "transfer", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "egldValue": "0,050000000000000000", + "gasLimit": "50,000" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "proposeAsyncCall", + "arguments": [ + "0x000000000000000000010000000000000000000000000000000000000002ffff", + "0xb1a2bc2ec50000", + "0x7265676973746572416e64536574416c6c526f6c6573", + "0x54657374436f6c6c656374696f6e31", + "0x54455354434f4c4c31", + "0x4e4654", + "0x" + ], + "gasLimit": "10,000,000", + "gasPrice": "" + }, + "expect": { + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TESTCOLL1-636884" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "performAction", + "arguments": [ + "0x01" + ], + "gasLimit": "80,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "proposeAsyncCall", + "arguments": [ + "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "0x", + "0x455344544e4654437265617465", + "0x54455354434f4c4c312d363336383834", + "0x01", + "0x5465737420636f6c6c656374696f6e206974656d202330", + "0x0bb8", + "0x", + "0x746167733a746573742c727573742d696e7465726163746f72", + "0x68747470733a2f2f697066732e696f2f697066732f516d5979416145663170684a53356d4e3677666f7535646535476270556464427854593156656b4b636a643550432f6e667430302e706e67" + ], + "gasLimit": "10,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "proposeAsyncCall", + "arguments": [ + "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "0x", + "0x455344544e4654437265617465", + "0x54455354434f4c4c312d363336383834", + "0x01", + "0x5465737420636f6c6c656374696f6e206974656d202331", + "0x0bb8", + "0x", + "0x746167733a746573742c727573742d696e7465726163746f72", + "0x68747470733a2f2f697066732e696f2f697066732f516d5979416145663170684a53356d4e3677666f7535646535476270556464427854593156656b4b636a643550432f6e667430312e706e67" + ], + "gasLimit": "10,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "proposeAsyncCall", + "arguments": [ + "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "0x", + "0x455344544e4654437265617465", + "0x54455354434f4c4c312d363336383834", + "0x01", + "0x5465737420636f6c6c656374696f6e206974656d202332", + "0x0bb8", + "0x", + "0x746167733a746573742c727573742d696e7465726163746f72", + "0x68747470733a2f2f697066732e696f2f697066732f516d5979416145663170684a53356d4e3677666f7535646535476270556464427854593156656b4b636a643550432f6e667430322e706e67" + ], + "gasLimit": "10,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x02" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x02" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x02" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x03" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x03" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x03" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x04" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xb13a017423c366caff8cecfb77a12610a130f4888134122c7937feae0d6d7d17", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x04" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x3af8d9c9423b2577c6252722c1d90212a4111f7203f9744f76fcfa1d0a310033", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "sign", + "arguments": [ + "0x04" + ], + "gasLimit": "15,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "performAction", + "arguments": [ + "0x02" + ], + "gasLimit": "30,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "performAction", + "arguments": [ + "0x03" + ], + "gasLimit": "30,000,000", + "gasPrice": "" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x000000000000000005008a3621a73196c9a9539f05be7d3c277346cdc989ed60", + "function": "performAction", + "arguments": [ + "0x04" + ], + "gasLimit": "30,000,000", + "gasPrice": "" + } + } + ] +} \ No newline at end of file diff --git a/contracts/examples/multisig/scenarios/interactor_trace.scen.json b/contracts/examples/multisig/scenarios/interactor_wegld.scen.json similarity index 100% rename from contracts/examples/multisig/scenarios/interactor_trace.scen.json rename to contracts/examples/multisig/scenarios/interactor_wegld.scen.json diff --git a/contracts/examples/multisig/tests/multisig_scenario_go_test.rs b/contracts/examples/multisig/tests/multisig_scenario_go_test.rs index 5335581336..6e7fc7464e 100644 --- a/contracts/examples/multisig/tests/multisig_scenario_go_test.rs +++ b/contracts/examples/multisig/tests/multisig_scenario_go_test.rs @@ -55,8 +55,20 @@ fn deploy_duplicate_bm_go() { } #[test] -fn interactor_trace_go() { - world().run("scenarios/interactor_trace.scen.json"); +#[ignore = "system SC not yet implemented"] +fn interactor_nft_go() { + world().run("scenarios/interactor_nft.scen.json"); +} + +#[test] +#[ignore = "system SC not yet implemented"] +fn interactor_nft_all_roles_go() { + world().run("scenarios/interactor_nft_all_roles.scen.json"); +} + +#[test] +fn interactor_wegld_go() { + world().run("scenarios/interactor_wegld.scen.json"); } #[test] diff --git a/contracts/examples/multisig/tests/multisig_scenario_rs_test.rs b/contracts/examples/multisig/tests/multisig_scenario_rs_test.rs index 1b78711bb0..27d286e1d9 100644 --- a/contracts/examples/multisig/tests/multisig_scenario_rs_test.rs +++ b/contracts/examples/multisig/tests/multisig_scenario_rs_test.rs @@ -82,8 +82,18 @@ fn deploy_duplicate_bm_rs() { } #[test] -fn interactor_trace_rs() { - world().run("scenarios/interactor_trace.scen.json"); +fn interactor_nft_rs() { + world().run("scenarios/interactor_nft.scen.json"); +} + +#[test] +fn interactor_nft_all_roles_rs() { + world().run("scenarios/interactor_nft_all_roles.scen.json"); +} + +#[test] +fn interactor_wegld_rs() { + world().run("scenarios/interactor_wegld.scen.json"); } #[test] diff --git a/framework/scenario/src/scenario/run_vm/set_state.rs b/framework/scenario/src/scenario/run_vm/set_state.rs index 76c608d678..c09804ae1b 100644 --- a/framework/scenario/src/scenario/run_vm/set_state.rs +++ b/framework/scenario/src/scenario/run_vm/set_state.rs @@ -76,6 +76,9 @@ fn execute(state: &mut BlockchainState, set_state_step: &SetStateStep) { new_address.new_address.to_vm_address(), ) } + for new_token_identifier in set_state_step.new_token_identifiers.iter().cloned() { + state.put_new_token_identifier(new_token_identifier) + } if let Some(block_info_obj) = &*set_state_step.previous_block_info { update_block_info(&mut state.previous_block_info, block_info_obj); } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index f76841b320..0790b01343 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -26,6 +26,7 @@ rand = "0.8.5" rand_seeder = "0.2.2" ed25519-dalek = "1.0.1" itertools = "0.10.3" +hex-literal = "0.3.1" bitflags = "1.3.2" [dependencies.multiversx-chain-vm-executor] diff --git a/vm/src/tx_execution.rs b/vm/src/tx_execution.rs index d2ee925d82..a3082074b9 100644 --- a/vm/src/tx_execution.rs +++ b/vm/src/tx_execution.rs @@ -4,6 +4,7 @@ mod exec_call; mod exec_contract_endpoint; mod exec_create; mod exec_general_tx; +mod system_sc; pub use blockchain_vm::{BlockchainVM, BlockchainVMRef}; pub use builtin_function_mocks::*; @@ -11,3 +12,4 @@ pub use exec_call::*; pub use exec_contract_endpoint::*; pub use exec_create::*; pub use exec_general_tx::*; +pub use system_sc::*; diff --git a/vm/src/tx_execution/exec_general_tx.rs b/vm/src/tx_execution/exec_general_tx.rs index 1cdc3d0641..3fd572abd4 100644 --- a/vm/src/tx_execution/exec_general_tx.rs +++ b/vm/src/tx_execution/exec_general_tx.rs @@ -1,6 +1,7 @@ use num_traits::Zero; use crate::{ + tx_execution::execute_system_sc, tx_mock::{ BlockchainUpdate, TxCache, TxContext, TxContextStack, TxFunctionName, TxInput, TxLog, TxResult, @@ -9,7 +10,7 @@ use crate::{ with_shared::Shareable, }; -use super::BlockchainVMRef; +use super::{is_system_sc_address, BlockchainVMRef}; fn should_execute_sc_call(tx_input: &TxInput) -> bool { // execute whitebox calls no matter what @@ -37,29 +38,24 @@ impl BlockchainVMRef { where F: FnOnce(), { - let tx_context = TxContext::new(self.clone(), tx_input, tx_cache); - let mut tx_context_sh = Shareable::new(tx_context); - - if let Err(err) = tx_context_sh.tx_cache.transfer_egld_balance( - &tx_context_sh.tx_input_box.from, - &tx_context_sh.tx_input_box.to, - &tx_context_sh.tx_input_box.egld_value, - ) { + if let Err(err) = + tx_cache.transfer_egld_balance(&tx_input.from, &tx_input.to, &tx_input.egld_value) + { return (TxResult::from_panic_obj(&err), BlockchainUpdate::empty()); } // skip for transactions coming directly from scenario json, which should all be coming from user wallets // TODO: reorg context logic - let add_transfer_log = tx_context_sh.tx_input_box.from.is_smart_contract_address() - && !tx_context_sh.tx_input_box.egld_value.is_zero(); + let add_transfer_log = + tx_input.from.is_smart_contract_address() && !tx_input.egld_value.is_zero(); let transfer_value_log = if add_transfer_log { Some(TxLog { address: VMAddress::zero(), // TODO: figure out the real VM behavior endpoint: "transferValueOnly".into(), topics: vec![ - tx_context_sh.tx_input_box.from.to_vec(), - tx_context_sh.tx_input_box.to.to_vec(), - tx_context_sh.tx_input_box.egld_value.to_bytes_be(), + tx_input.from.to_vec(), + tx_input.to.to_vec(), + tx_input.egld_value.to_bytes_be(), ], data: Vec::new(), }) @@ -68,10 +64,10 @@ impl BlockchainVMRef { }; // TODO: temporary, will convert to explicit builtin function first - for esdt_transfer in tx_context_sh.tx_input_box.esdt_values.iter() { - let transfer_result = tx_context_sh.tx_cache.transfer_esdt_balance( - &tx_context_sh.tx_input_box.from, - &tx_context_sh.tx_input_box.to, + for esdt_transfer in tx_input.esdt_values.iter() { + let transfer_result = tx_cache.transfer_esdt_balance( + &tx_input.from, + &tx_input.to, &esdt_transfer.token_identifier, esdt_transfer.nonce, &esdt_transfer.value, @@ -81,11 +77,20 @@ impl BlockchainVMRef { } } - if should_execute_sc_call(&tx_context_sh.tx_input_box) { + let (mut tx_result, blockchain_updates) = if is_system_sc_address(&tx_input.to) { + execute_system_sc(tx_input, tx_cache) + } else if should_execute_sc_call(&tx_input) { + let tx_context = TxContext::new(self.clone(), tx_input, tx_cache); + let mut tx_context_sh = Shareable::new(tx_context); + TxContextStack::execute_on_vm_stack(&mut tx_context_sh, f); + + tx_context_sh.into_inner().into_results() + } else { + // no execution + (TxResult::empty(), tx_cache.into_blockchain_updates()) }; - let (mut tx_result, blockchain_updates) = tx_context_sh.into_inner().into_results(); if let Some(tv_log) = transfer_value_log { tx_result.result_logs.insert(0, tv_log); } diff --git a/vm/src/tx_execution/system_sc.rs b/vm/src/tx_execution/system_sc.rs new file mode 100644 index 0000000000..ed28fecd8f --- /dev/null +++ b/vm/src/tx_execution/system_sc.rs @@ -0,0 +1,60 @@ +mod system_sc_issue; +mod system_sc_special_roles; +mod system_sc_unimplemented; + +use crate::{ + tx_mock::{BlockchainUpdate, TxCache, TxInput, TxResult}, + types::VMAddress, +}; +use hex_literal::hex; +use system_sc_issue::*; +use system_sc_special_roles::*; +use system_sc_unimplemented::*; + +/// Address of the system smart contract that manages ESDT. +/// Bech32: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u +pub const ESDT_SYSTEM_SC_ADDRESS_ARRAY: [u8; 32] = + hex!("000000000000000000010000000000000000000000000000000000000002ffff"); + +pub fn is_system_sc_address(address: &VMAddress) -> bool { + address.as_array() == &ESDT_SYSTEM_SC_ADDRESS_ARRAY +} + +pub fn execute_system_sc(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + let func_name = &tx_input.func_name; + match func_name.as_str() { + "issue" => issue(tx_input, tx_cache), + "issueSemiFungible" => issue_semi_fungible(tx_input, tx_cache), + "issueNonFungible" => issue_non_fungible(tx_input, tx_cache), + "registerMetaESDT" => register_meta_esdt(tx_input, tx_cache), + "changeSFTToMetaESDT" => change_sft_to_meta_esdt(tx_input, tx_cache), + "registerAndSetAllRoles" => register_and_set_all_roles(tx_input, tx_cache), + "ESDTBurn" => esdt_burn(tx_input, tx_cache), + "mint" => mint(tx_input, tx_cache), + "freeze" => freeze(tx_input, tx_cache), + "unFreeze" => unfreeze(tx_input, tx_cache), + "wipe" => wipe(tx_input, tx_cache), + "pause" => pause(tx_input, tx_cache), + "unPause" => unpause(tx_input, tx_cache), + "freezeSingleNFT" => freeze_single_nft(tx_input, tx_cache), + "unFreezeSingleNFT" => unfreeze_single_nft(tx_input, tx_cache), + "wipeSingleNFT" => wipe_single_nft(tx_input, tx_cache), + "claim" => claim(tx_input, tx_cache), + "configChange" => config_change(tx_input, tx_cache), + "controlChanges" => control_changes(tx_input, tx_cache), + "transferOwnership" => transfer_ownership(tx_input, tx_cache), + "getTokenProperties" => get_token_properties(tx_input, tx_cache), + "getSpecialRoles" => get_special_roles(tx_input, tx_cache), + "setSpecialRole" => set_special_role(tx_input, tx_cache), + "unSetSpecialRole" => unset_special_role(tx_input, tx_cache), + "transferNFTCreateRole" => transfer_nft_create_role(tx_input, tx_cache), + "stopNFTCreate" => stop_nft_create(tx_input, tx_cache), + "getAllAddressesAndRoles" => get_all_addresses_and_roles(tx_input, tx_cache), + "getContractConfig" => get_contract_config(tx_input, tx_cache), + "changeToMultiShardCreate" => change_to_multi_shard_create(tx_input, tx_cache), + "setBurnRoleGlobally" => set_burn_role_globally(tx_input, tx_cache), + "unsetBurnRoleGlobally" => unset_burn_role_globally(tx_input, tx_cache), + "sendAllTransferRoleAddresses" => send_all_transfer_role_addresses(tx_input, tx_cache), + invalid_func_name => panic!("invalid system SC function: {invalid_func_name}"), + } +} diff --git a/vm/src/tx_execution/system_sc/system_sc_issue.rs b/vm/src/tx_execution/system_sc/system_sc_issue.rs new file mode 100644 index 0000000000..dd787c61e2 --- /dev/null +++ b/vm/src/tx_execution/system_sc/system_sc_issue.rs @@ -0,0 +1,169 @@ +use num_bigint::BigUint; + +use crate::{ + crypto_functions::keccak256, + tx_mock::{BlockchainUpdate, TxCache, TxInput, TxResult}, + types::{top_decode_u64, VMTokenType}, +}; + +/// Issues a new fungible token. +#[allow(unused_variables)] +pub fn issue(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + if tx_input.args.len() < 4 { + let tx_result = TxResult::from_vm_error("not enough arguments"); + return (tx_result, BlockchainUpdate::empty()); + } + let name = tx_input.args[0].clone(); + let ticker = tx_input.args[1].clone(); + let total_supply = BigUint::from_bytes_be(tx_input.args[2].clone().as_ref()); + let decimals = top_decode_u64(tx_input.args[3].clone().as_ref()) as u32; + + register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::Fungible) +} + +/// Issues a new semi-fungible token. +#[allow(unused_variables)] +pub fn issue_semi_fungible(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + if tx_input.args.len() < 2 { + let tx_result = TxResult::from_vm_error("not enough arguments"); + return (tx_result, BlockchainUpdate::empty()); + } + let name = tx_input.args[0].clone(); + let ticker = tx_input.args[1].clone(); + + register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::SemiFungible) +} + +/// Issues a new non-fungible token. +#[allow(unused_variables)] +pub fn issue_non_fungible(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + if tx_input.args.len() < 2 { + let tx_result = TxResult::from_vm_error("not enough arguments"); + return (tx_result, BlockchainUpdate::empty()); + } + let name = tx_input.args[0].clone(); + let ticker = tx_input.args[1].clone(); + + register_and_set_roles(tx_input, tx_cache, ticker, VMTokenType::NonFungible) +} + +// Issues a new token and sets all roles for its type. +#[allow(unused_variables)] +pub fn register_and_set_all_roles( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + if tx_input.args.len() < 4 { + let tx_result = TxResult::from_vm_error("not enough arguments"); + return (tx_result, BlockchainUpdate::empty()); + } + + let name = tx_input.args[0].clone(); + let ticker = tx_input.args[1].clone(); + let token_type = VMTokenType::from_system_sc_arg(&tx_input.args[2]); + let decimals = top_decode_u64(tx_input.args[3].clone().as_ref()) as u32; + + register_and_set_roles(tx_input, tx_cache, ticker, token_type) +} + +fn register_and_set_roles( + tx_input: TxInput, + tx_cache: TxCache, + ticker: Vec, + token_type: VMTokenType, +) -> (TxResult, BlockchainUpdate) { + let mut new_token_identifiers = tx_cache.get_new_token_identifiers(); + + let token_identifier = if let Some((i, ti)) = + first_token_identifier_with_ticker(&new_token_identifiers, &ticker) + { + new_token_identifiers.remove(i); + ti.into_bytes() + } else { + generate_token_identifier_from_ticker(&tx_input, &tx_cache, &ticker) + }; + + tx_cache.with_account_mut(&tx_input.from, |account| { + account + .esdt + .register_and_set_roles(&token_identifier, token_type); + }); + tx_cache.set_new_token_identifiers(new_token_identifiers); + + let tx_result = TxResult { + result_values: vec![token_identifier], + ..Default::default() + }; + + (tx_result, tx_cache.into_blockchain_updates()) +} + +fn first_token_identifier_with_ticker( + token_identifiers: &[String], + ticker: &[u8], +) -> Option<(usize, String)> { + let extract_ticker = + |ti: &String| -> String { ti.split('-').map(|x| x.to_string()).next().unwrap() }; + + token_identifiers + .iter() + .position(|x| extract_ticker(x).as_bytes() == ticker) + .map(|i| (i, token_identifiers[i].clone())) +} + +fn generate_token_identifier_from_ticker( + tx_input: &TxInput, + tx_cache: &TxCache, + ticker: &[u8], +) -> Vec { + let new_random_base = [ + tx_input.from.as_bytes(), + tx_cache + .blockchain_ref() + .current_block_info + .block_random_seed + .as_slice(), + ] + .concat(); + let new_random = keccak256(&new_random_base); + let new_random_for_ticker = &new_random[..3]; + + let token_identifier = [ + ticker, + "-".as_bytes(), + hex::encode(new_random_for_ticker).as_bytes(), + ] + .concat(); + + token_identifier +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_first_token_identifier_with_ticker_ok() { + let ticker = String::from("BBBB").into_bytes(); + let new_token_indetifiers = vec![ + "AAAA-0123".to_string(), + "BBBB-4567".to_string(), + "BBBB-0123".to_string(), + "CCCC-4567".to_string(), + ]; + + let ti = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker); + let expected = b"BBBB-4567".as_slice(); + assert_eq!(expected, ti.unwrap().1.into_bytes()); + } + + #[test] + fn test_first_token_identifier_with_ticker_is_none() { + let ticker = String::from("BBBB").into_bytes(); + let new_token_indetifiers = vec!["AAAA-0123".to_string()]; + + let i = first_token_identifier_with_ticker(&new_token_indetifiers, &ticker); + let expected = None; + assert_eq!(expected, i); + } +} diff --git a/vm/src/tx_execution/system_sc/system_sc_special_roles.rs b/vm/src/tx_execution/system_sc/system_sc_special_roles.rs new file mode 100644 index 0000000000..17beef2266 --- /dev/null +++ b/vm/src/tx_execution/system_sc/system_sc_special_roles.rs @@ -0,0 +1,23 @@ +use crate::{ + tx_mock::{BlockchainUpdate, TxCache, TxInput, TxResult}, + types::VMAddress, +}; + +pub fn set_special_role(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + if tx_input.args.len() < 3 { + return ( + TxResult::from_vm_error("setSpecialRole too few arguments"), + BlockchainUpdate::empty(), + ); + } + + let token_identifier = tx_input.args[0].clone(); + let address = VMAddress::from_slice(tx_input.args[1].as_slice()); + let role = tx_input.args[2].clone(); + + tx_cache.with_account_mut(&address, |account| { + account.esdt.set_special_role(&token_identifier, &role); + }); + + (TxResult::empty(), tx_cache.into_blockchain_updates()) +} diff --git a/vm/src/tx_execution/system_sc/system_sc_unimplemented.rs b/vm/src/tx_execution/system_sc/system_sc_unimplemented.rs new file mode 100644 index 0000000000..cf93be7727 --- /dev/null +++ b/vm/src/tx_execution/system_sc/system_sc_unimplemented.rs @@ -0,0 +1,135 @@ +#![allow(unused_variables)] + +use crate::tx_mock::{BlockchainUpdate, TxCache, TxInput, TxResult}; + +/// Every unimplemented fn will be implemented and moved to its corresponding file. +/// This file will be deleted. + +pub fn register_meta_esdt(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn change_sft_to_meta_esdt( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn esdt_burn(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn mint(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn freeze(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn unfreeze(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn wipe(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn pause(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn unpause(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn freeze_single_nft(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn unfreeze_single_nft(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn wipe_single_nft(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn claim(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn config_change(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn control_changes(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn transfer_ownership(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn get_token_properties(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn get_special_roles(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn unset_special_role(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn transfer_nft_create_role( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn stop_nft_create(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn get_all_addresses_and_roles( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn get_contract_config(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn change_to_multi_shard_create( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn set_burn_role_globally( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn unset_burn_role_globally( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} + +pub fn send_all_transfer_role_addresses( + tx_input: TxInput, + tx_cache: TxCache, +) -> (TxResult, BlockchainUpdate) { + unimplemented!() +} diff --git a/vm/src/tx_mock/blockchain_update.rs b/vm/src/tx_mock/blockchain_update.rs index f924d44bd9..0c78626a93 100644 --- a/vm/src/tx_mock/blockchain_update.rs +++ b/vm/src/tx_mock/blockchain_update.rs @@ -5,18 +5,22 @@ use crate::{ world_mock::{AccountData, BlockchainState}, }; +#[derive(Default)] pub struct BlockchainUpdate { pub accounts: HashMap, + pub new_token_identifiers: Option>, } impl BlockchainUpdate { pub fn empty() -> Self { - BlockchainUpdate { - accounts: HashMap::new(), - } + BlockchainUpdate::default() } pub fn apply(self, blockchain: &mut BlockchainState) { blockchain.update_accounts(self.accounts); + + if let Some(token_identifiers) = self.new_token_identifiers { + blockchain.update_new_token_identifiers(token_identifiers); + } } } diff --git a/vm/src/tx_mock/tx_cache.rs b/vm/src/tx_mock/tx_cache.rs index 56ed2765a5..8dc311bf2c 100644 --- a/vm/src/tx_mock/tx_cache.rs +++ b/vm/src/tx_mock/tx_cache.rs @@ -16,6 +16,7 @@ use super::{BlockchainUpdate, TxCacheSource}; pub struct TxCache { source_ref: Rc, pub(super) accounts: RefCell>, + pub(super) new_token_identifiers: RefCell>>, } impl fmt::Debug for TxCache { @@ -31,6 +32,7 @@ impl TxCache { TxCache { source_ref, accounts: RefCell::new(HashMap::new()), + new_token_identifiers: RefCell::new(None), } } @@ -97,9 +99,18 @@ impl TxCache { }) } + pub fn get_new_token_identifiers(&self) -> Vec { + self.blockchain_ref().get_new_token_identifiers() + } + + pub fn set_new_token_identifiers(&self, token_identifiers: Vec) { + *self.new_token_identifiers.borrow_mut() = Some(token_identifiers); + } + pub fn into_blockchain_updates(self) -> BlockchainUpdate { BlockchainUpdate { accounts: self.accounts.into_inner(), + new_token_identifiers: self.new_token_identifiers.into_inner(), } } diff --git a/vm/src/tx_mock/tx_cache_balance_util.rs b/vm/src/tx_mock/tx_cache_balance_util.rs index 20a0aa9ad7..97eb5fb1a5 100644 --- a/vm/src/tx_mock/tx_cache_balance_util.rs +++ b/vm/src/tx_mock/tx_cache_balance_util.rs @@ -1,6 +1,9 @@ use num_bigint::BigUint; -use crate::{tx_mock::TxPanic, types::VMAddress, world_mock::EsdtInstanceMetadata}; +use crate::{ + tx_execution::is_system_sc_address, tx_mock::TxPanic, types::VMAddress, + world_mock::EsdtInstanceMetadata, +}; use super::TxCache; @@ -89,8 +92,12 @@ impl TxCache { to: &VMAddress, value: &BigUint, ) -> Result<(), TxPanic> { - self.subtract_egld_balance(from, value)?; - self.increase_egld_balance(to, value); + if !is_system_sc_address(from) { + self.subtract_egld_balance(from, value)?; + } + if !is_system_sc_address(to) { + self.increase_egld_balance(to, value); + } Ok(()) } @@ -102,8 +109,10 @@ impl TxCache { nonce: u64, value: &BigUint, ) -> Result<(), TxPanic> { - let metadata = self.subtract_esdt_balance(from, esdt_token_identifier, nonce, value)?; - self.increase_esdt_balance(to, esdt_token_identifier, nonce, value, metadata); + if !is_system_sc_address(from) && !is_system_sc_address(to) { + let metadata = self.subtract_esdt_balance(from, esdt_token_identifier, nonce, value)?; + self.increase_esdt_balance(to, esdt_token_identifier, nonce, value, metadata); + } Ok(()) } } diff --git a/vm/src/types.rs b/vm/src/types.rs index c242d61cd2..d1ada0c0f6 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -3,6 +3,7 @@ mod vm_code_metadata; mod vm_esdt_local_role; mod vm_esdt_local_role_flags; mod vm_h256; +mod vm_token_type; use num_bigint::BigUint; use num_traits::Zero; @@ -11,6 +12,7 @@ pub use vm_code_metadata::VMCodeMetadata; pub use vm_esdt_local_role::EsdtLocalRole; pub use vm_esdt_local_role_flags::EsdtLocalRoleFlags; pub use vm_h256::H256; +pub use vm_token_type::VMTokenType; pub type RawHandle = i32; diff --git a/vm/src/types/vm_token_type.rs b/vm/src/types/vm_token_type.rs new file mode 100644 index 0000000000..18670a90dc --- /dev/null +++ b/vm/src/types/vm_token_type.rs @@ -0,0 +1,19 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VMTokenType { + Fungible, + SemiFungible, + Meta, + NonFungible, +} + +impl VMTokenType { + pub fn from_system_sc_arg(raw: &[u8]) -> Self { + match raw { + b"FNG" => VMTokenType::Fungible, + b"SFT" => VMTokenType::SemiFungible, + b"META" => VMTokenType::Meta, + b"NFT" => VMTokenType::NonFungible, + _ => panic!("invalid token type"), + } + } +} diff --git a/vm/src/world_mock/blockchain_mock.rs b/vm/src/world_mock/blockchain_mock.rs index d4017f01a8..0113ea3520 100644 --- a/vm/src/world_mock/blockchain_mock.rs +++ b/vm/src/world_mock/blockchain_mock.rs @@ -1,9 +1,6 @@ use crate::{tx_execution::BlockchainVMRef, with_shared::Shareable}; use multiversx_chain_vm_executor::Executor; -use std::{ - fmt::Debug, - ops::{Deref, DerefMut}, -}; +use std::{fmt::Debug, ops::Deref}; use super::{BlockchainState, FailingExecutor}; @@ -27,19 +24,6 @@ impl Default for BlockchainMock { } } -impl BlockchainMock { - pub fn with_borrowed(&mut self, f: F) -> R - where - F: FnOnce(BlockchainVMRef, BlockchainState) -> (R, BlockchainState), - { - let state_mut = self.state.deref_mut(); - let obj = std::mem::take(state_mut); - let (result, obj) = f(self.vm.clone(), obj); - *state_mut = obj; - result - } -} - impl Debug for BlockchainMock { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BlockchainMock") diff --git a/vm/src/world_mock/blockchain_state.rs b/vm/src/world_mock/blockchain_state.rs index e27ca83bac..28a339f54b 100644 --- a/vm/src/world_mock/blockchain_state.rs +++ b/vm/src/world_mock/blockchain_state.rs @@ -13,6 +13,7 @@ pub struct BlockchainState { pub new_addresses: HashMap<(VMAddress, u64), VMAddress>, pub previous_block_info: BlockInfo, pub current_block_info: BlockInfo, + pub new_token_identifiers: Vec, } impl BlockchainState { @@ -68,6 +69,18 @@ impl BlockchainState { .storage .insert(STORAGE_REWARD_KEY.to_vec(), storage_v_rew.to_bytes_be()); } + + pub fn put_new_token_identifier(&mut self, token_identifier: String) { + self.new_token_identifiers.push(token_identifier) + } + + pub fn get_new_token_identifiers(&self) -> Vec { + self.new_token_identifiers.clone() + } + + pub fn update_new_token_identifiers(&mut self, token_identifiers: Vec) { + self.new_token_identifiers = token_identifiers; + } } impl Debug for BlockchainState { diff --git a/vm/src/world_mock/esdt_data.rs b/vm/src/world_mock/esdt_data.rs index 3155a62408..4d7093aa2e 100644 --- a/vm/src/world_mock/esdt_data.rs +++ b/vm/src/world_mock/esdt_data.rs @@ -1,7 +1,7 @@ use num_bigint::BigUint; use num_traits::Zero; -use crate::display_util::key_hex; +use crate::{display_util::key_hex, types::VMTokenType}; use std::{ collections::{hash_map::Iter, HashMap}, fmt::{self, Write}, @@ -149,6 +149,58 @@ impl AccountEsdt { pub fn iter(&self) -> Iter, EsdtData> { self.0.iter() } + + pub fn set_special_role(&mut self, token_identifier: &[u8], role: &[u8]) { + if let Some(esdt_data) = self.get_mut_by_identifier(token_identifier) { + let roles = esdt_data.roles.get(); + if !roles.contains(role.to_vec().as_ref()) { + let mut new_roles = roles; + new_roles.push(role.to_vec()); + esdt_data.roles = EsdtRoles::new(new_roles); + } + } + } + + pub fn register_and_set_roles(&mut self, token_identifier: &[u8], token_type: VMTokenType) { + self.issue_token(token_identifier); + self.set_roles( + token_identifier.to_vec(), + Self::get_all_roles_for_token_type(token_type), + ); + } + + fn issue_token(&mut self, token_identifier: &[u8]) { + self.0.insert( + token_identifier.to_vec(), + EsdtData { + instances: EsdtInstances::new(), + last_nonce: 0, + roles: EsdtRoles::default(), + frozen: false, + }, + ); + } + + fn get_all_roles_for_token_type(token_type: VMTokenType) -> Vec> { + match token_type { + VMTokenType::NonFungible => vec![ + "ESDTRoleNFTCreate".as_bytes().to_vec(), + "ESDTRoleNFTBurn".as_bytes().to_vec(), + "ESDTRoleNFTUpdateAttributes".as_bytes().to_vec(), + "ESDTRoleNFTAddURI".as_bytes().to_vec(), + ], + VMTokenType::SemiFungible | VMTokenType::Meta => vec![ + "ESDTRoleNFTCreate".as_bytes().to_vec(), + "ESDTRoleNFTBurn".as_bytes().to_vec(), + "ESDTRoleNFTAddQuantity".as_bytes().to_vec(), + ], + VMTokenType::Fungible => vec![ + "ESDTRoleLocalMint".as_bytes().to_vec(), + "ESDTRoleLocalBurn".as_bytes().to_vec(), + "ESDTRoleLocalTransfer".as_bytes().to_vec(), + ], + } + } } impl fmt::Display for EsdtData {