diff --git a/Cargo.lock b/Cargo.lock index d32c6df71..c0c2c14cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -178,6 +187,12 @@ dependencies = [ "subtle 1.0.0", ] +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + [[package]] name = "digest" version = "0.8.1" @@ -202,12 +217,33 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "downcast" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" + [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "float-cmp" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fragile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2" + [[package]] name = "generic-array" version = "0.12.4" @@ -260,6 +296,12 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.98" @@ -312,6 +354,64 @@ dependencies = [ "snafu", ] +[[package]] +name = "mock_band" +version = "0.1.0" +dependencies = [ + "bincode", + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "mockall", + "schemars", + "secret-toolkit", + "serde", + "shade-protocol", + "snafu", +] + +[[package]] +name = "mockall" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab571328afa78ae322493cacca3efac6a0f2e0a67305b4df31fd439ef129ac0" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e25b214433f669161f414959594216d8e6ba83b6679d3db96899c0b4639033" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.26.0" @@ -341,6 +441,7 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", + "mockall", "schemars", "secret-toolkit", "serde", @@ -354,6 +455,35 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "predicates" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" +dependencies = [ + "difference", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" + +[[package]] +name = "predicates-tree" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d" +dependencies = [ + "predicates-core", + "treeline", +] + [[package]] name = "proc-macro2" version = "1.0.28" @@ -408,6 +538,23 @@ dependencies = [ "rand_core", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "rustc-demangle" version = "0.1.20" @@ -655,6 +802,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "treeline" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" + [[package]] name = "typenum" version = "1.13.0" diff --git a/contracts/compiled/checksum/mint.txt b/contracts/compiled/checksum/mint.txt index b8815b80d..d563e97ba 100644 --- a/contracts/compiled/checksum/mint.txt +++ b/contracts/compiled/checksum/mint.txt @@ -1 +1 @@ -02404f16eddfbb6aee763267f8e48061 +f65b887bcc5bd6bedee459969c167818 diff --git a/contracts/compiled/checksum/mock_band.txt b/contracts/compiled/checksum/mock_band.txt index 0a6b1042d..964d86b34 100644 --- a/contracts/compiled/checksum/mock_band.txt +++ b/contracts/compiled/checksum/mock_band.txt @@ -1 +1 @@ -8382e8e8f905f9a0dabf8079ff5ee47a +581bb67ce7144b7993190b46ece45893 diff --git a/contracts/compiled/checksum/oracle.txt b/contracts/compiled/checksum/oracle.txt index 5f75c843e..ca921c0ee 100644 --- a/contracts/compiled/checksum/oracle.txt +++ b/contracts/compiled/checksum/oracle.txt @@ -1 +1 @@ -3fdc7dfd0d219cba0a571f6042510980 +ef8dc00f91dbedbff4f39fcb7161146c diff --git a/contracts/compiled/contractlib/contractlib.py b/contracts/compiled/contractlib/contractlib.py index a89dbec8e..760fb9d11 100644 --- a/contracts/compiled/contractlib/contractlib.py +++ b/contracts/compiled/contractlib/contractlib.py @@ -2,7 +2,7 @@ class PreInstantiatedContract: - def __init__(self, contract_id, address, code_hash): + def __init__(self, address, code_hash): self.address = address self.code_hash = code_hash diff --git a/contracts/compiled/contractlib/mintlib.py b/contracts/compiled/contractlib/mintlib.py index 3a3dc7d40..2a5f40ba0 100644 --- a/contracts/compiled/contractlib/mintlib.py +++ b/contracts/compiled/contractlib/mintlib.py @@ -6,10 +6,11 @@ class Mint(Contract): - def __init__(self, label, silk, oracle, contract='mint.wasm.gz', admin='a', uploader='a', gas='10000000', + def __init__(self, label, silk, shade, oracle, contract='mint.wasm.gz', admin='a', uploader='a', gas='10000000', backend='test', instantiated_contract=None, code_id=None): init_msg = json.dumps( {"silk": {"address": silk.address, "code_hash": silk.code_hash}, + "shade": {"address": shade.address, "code_hash": shade.code_hash}, "oracle": {"address": oracle.address, "code_hash": oracle.code_hash}}) super().__init__(contract, init_msg, label, admin, uploader, gas, backend, instantiated_contract=instantiated_contract, code_id=code_id) @@ -34,7 +35,7 @@ def migrate(self, label, code_id, code_hash): new_mint.code_hash = code_hash return new_mint - def update_config(self, owner=None, silk=None, oracle=None): + def update_config(self, owner=None, silk=None, shade=None, oracle=None): """ Updates the minting contract's config :param owner: New admin @@ -51,6 +52,12 @@ def update_config(self, owner=None, silk=None, oracle=None): "code_hash": silk.code_hash } raw_msg["update_config"]["silk"] = contract + if shade is not None: + contract = { + "address": shade.address, + "code_hash": shade.code_hash + } + raw_msg["update_config"]["shade"] = contract if oracle is not None: contract = { "address": oracle.address, diff --git a/contracts/compiled/contractlib/secretlib/secretlib.py b/contracts/compiled/contractlib/secretlib/secretlib.py index 1235916b2..19c0f8f1e 100644 --- a/contracts/compiled/contractlib/secretlib/secretlib.py +++ b/contracts/compiled/contractlib/secretlib/secretlib.py @@ -4,7 +4,7 @@ # Presetup some commands query_list_code = ['secretcli', 'query', 'compute', 'list-code'] -MAX_RETRY = 10 +MAX_TRIES = 10 def run_command(command, wait=6): diff --git a/contracts/compiled/mint.wasm.gz b/contracts/compiled/mint.wasm.gz index 728b209bb..d8cf0f6ad 100644 Binary files a/contracts/compiled/mint.wasm.gz and b/contracts/compiled/mint.wasm.gz differ diff --git a/contracts/compiled/mock_band.wasm.gz b/contracts/compiled/mock_band.wasm.gz index 2296bfc8a..728c1c958 100644 Binary files a/contracts/compiled/mock_band.wasm.gz and b/contracts/compiled/mock_band.wasm.gz differ diff --git a/contracts/compiled/oracle.wasm.gz b/contracts/compiled/oracle.wasm.gz index ac421e6b8..3d32c53be 100644 Binary files a/contracts/compiled/oracle.wasm.gz and b/contracts/compiled/oracle.wasm.gz differ diff --git a/contracts/compiled/tester.py b/contracts/compiled/tester.py index 2ae20940f..615b182dd 100755 --- a/contracts/compiled/tester.py +++ b/contracts/compiled/tester.py @@ -33,11 +33,11 @@ print(f"\tReceived {sscrt_minted} usSCRT") assert sscrt_mint_amount == sscrt_minted, f"Minted {sscrt_minted}; expected {sscrt_mint_amount}" - print("Configuring silk") + print("Configuring Silk") silk = SNIP20(gen_label(8), decimals=6, public_total_supply=True, enable_mint=True, enable_burn=True) silk_password = silk.set_view_key(account_key, "password") - print("Configuring shade") + print("Configuring Shade") shade = SNIP20(gen_label(8), decimals=6, public_total_supply=True, enable_mint=True, enable_burn=True) shade_password = shade.set_view_key(account_key, "password") @@ -50,7 +50,7 @@ print(price / (10 ** 18)) print("Configuring Mint contract") - mint = Mint(gen_label(8), silk, oracle) + mint = Mint(gen_label(8), silk, shade, oracle) silk.set_minters([mint.address]) shade.set_minters([mint.address]) mint.register_asset(sscrt) @@ -66,21 +66,35 @@ total_sent = 0 for i in range(total_tests): - send_amount = random.randint(minimum_amount, int(total_amount / total_tests) - 1) + send_amount = random.randint(minimum_amount, int(total_amount / total_tests / 2) - 1) total_sent += send_amount print(f"\tSending {send_amount} usSCRT") - # {"snip_msg_hook": { - # "minimum_expected_amount": "1", - # "mint_type": {"mint_silk": {}}}} - mint_option = "eyJtaW5pbXVtX2V4cGVjdGVkX2Ftb3VudCI6ICIxIiwgIm1pbnRfdHlwZSI6IHsibWludF9zaWxrIjoge319fQ==" + # { + # "minimum_expected_amount": "1", + # "mint_type": {"mint_silk": {}}} + mint_silk = "eyJtaW5pbXVtX2V4cGVjdGVkX2Ftb3VudCI6ICIxIiwgIm1pbnRfdHlwZSI6IHsibWludF9zaWxrIjoge319fQ==" # This one will fail because mint will never exceed its expected amount # mint_option = "eyJtaW5pbXVtX2V4cGVjdGVkX2Ftb3VudCI6ICIxNTkzNzA1MTUzMzg1NjAwMDAiLCAibWludF90eXBlIjogeyJtaW50X3NpbGsiOiB7fX19" - print(sscrt.send(account_key, mint.address, send_amount, mint_option)) + # { + # "minimum_expected_amount": "1", + # "mint_type": {"mint_shade": {}}} + mint_shade = "eyJtaW5pbXVtX2V4cGVjdGVkX2Ftb3VudCI6ICIxIiwibWludF90eXBlIjogeyJtaW50X3NoYWRlIjoge319fQ==" + + mint_silk_response = sscrt.send(account_key, mint.address, send_amount, mint_silk) + if mint_silk_response["plaintext_error"] != "": + print(f"Silk mint error: {mint_silk_response['plaintext_error']}") + + mint_shade_response = sscrt.send(account_key, mint.address, send_amount, mint_shade) + if mint_shade_response["plaintext_error"] != "": + print(f"Shade mint error: {mint_shade_response['plaintext_error']}") + silk_minted = silk.get_balance(account, silk_password) + shade_minted = shade.get_balance(account, shade_password) # assert total_sent == int(silk_minted), f"Total minted {silk_minted}; expected {total_sent}" print(f"\tSilk balance: {silk_minted} uSILK") + print(f"\tShade balance: {shade_minted} uSHD") burned_amount = mint.get_asset(sscrt)["asset"]["asset"]["burned_tokens"] print(f"\tTotal burned: {burned_amount} usSCRT\n") # assert total_sent == int(burned_amount), f"Burnt {burned_amount}; expected {total_sent}" @@ -96,10 +110,11 @@ with open("testnet-contracts.json", "r") as json_file: contracts_config = json.load(json_file) - print("Configuring silk") + print("Configuring Silk") silk_updated = False if contracts_config["silk"]["address"] == "": - contracts_config["silk"]["label"] = f"oracle-{gen_label(8)}" + print("Instantiating Silk") + contracts_config["silk"]["label"] = f"silk-{gen_label(8)}" silk_instantiated_contract = None silk_updated = True else: @@ -119,7 +134,8 @@ print("Configuring shade") shade_updated = False if contracts_config["shade"]["address"] == "": - contracts_config["shade"]["label"] = f"oracle-{gen_label(8)}" + print("Instantiating Shade") + contracts_config["shade"]["label"] = f"shade-{gen_label(8)}" shade_instantiated_contract = None shade_updated = True else: @@ -146,24 +162,25 @@ print("Configuring Oracle") oracle_updated = False + band_contract = PreInstantiatedContract("secret1p0jtg47hhwuwgp4cjpc46m7qq6vyjhdsvy2nph", "77c854ea110315d5103a42b88d3e7b296ca245d8b095e668c69997b265a75ac5") with open("checksum/oracle.txt", 'r') as oracle_checksum: if oracle_checksum.readline().strip() == contracts_config["oracle"]["checksum"].strip(): oracle_instantiated_contract = PreInstantiatedContract( address=contracts_config["oracle"]["address"], code_hash=contracts_config["oracle"]["code_hash"]) - oracle = Oracle(contracts_config["oracle"]["label"], admin=account, uploader=account, backend=None, + oracle = Oracle(contracts_config["oracle"]["label"], band_contract, admin=account, uploader=account, backend=None, instantiated_contract=oracle_instantiated_contract, code_id=contracts_config["oracle"]["contract_id"]) else: print("Instantiating Oracle") oracle_updated = True contracts_config["oracle"]["label"] = f"oracle-{gen_label(8)}" - oracle = Oracle(contracts_config["oracle"]["label"], admin=account, uploader=account, backend=None) + oracle = Oracle(contracts_config["oracle"]["label"], band_contract, admin=account, uploader=account, backend=None) contracts_config["oracle"]["contract_id"] = oracle.contract_id contracts_config["oracle"]["address"] = oracle.address contracts_config["oracle"]["code_hash"] = oracle.code_hash - print(oracle.get_silk_price()) + print(oracle.get_scrt_price()) oracle.print() print("Configuring Mint") @@ -172,7 +189,7 @@ mint_instantiated_contract = PreInstantiatedContract( address=contracts_config["mint"]["address"], code_hash=contracts_config["mint"]["code_hash"]) - mint = Mint(contracts_config["mint"]["label"], silk, oracle, admin=account, uploader=account, backend=None, + mint = Mint(contracts_config["mint"]["label"], silk, shade, oracle, admin=account, uploader=account, backend=None, instantiated_contract=mint_instantiated_contract, code_id=contracts_config["mint"]["contract_id"]) if mint_checksum.readline().strip() != contracts_config["mint"]["checksum"].strip(): @@ -180,7 +197,7 @@ mint_updated = True label = f"mint-{gen_label(8)}" # TODO: upload and get codehash + id of the contract without instantiating to call the mint.migrate - new_mint = Mint(label, silk, oracle, admin=account, uploader=account, backend=None) + new_mint = Mint(label, silk, shade, oracle, admin=account, uploader=account, backend=None) # mint.migrate() mint = copy.deepcopy(new_mint) contracts_config["mint"]["label"] = label @@ -192,7 +209,6 @@ mint.update_config(silk=silk, oracle=oracle) if silk_updated or mint_updated: - # TODO: reset minters if mint updated silk.set_minters([mint.address]) if mint_updated: diff --git a/contracts/compiled/testnet-contracts.json b/contracts/compiled/testnet-contracts.json index f52471162..b30a31468 100644 --- a/contracts/compiled/testnet-contracts.json +++ b/contracts/compiled/testnet-contracts.json @@ -1,16 +1,16 @@ { "mint": { - "label": "mint", - "contract_id": 30092, - "address": "secret1g9rfxe43my6w9h76422er5ckgp9cp9smgtqnx8", - "code_hash": "20D0B41DFB650E0773F9B8DB9516C651B8D3275ED66C3D6077C8102A1D6AD73E", + "label": "mint-jAOjWiAY", + "contract_id": "30158", + "address": "secret1r2fl5rw39qlevvxf8p9lyk6e2scvg5qrwcn0ss", + "code_hash": "3ADD3511612AFB22C664422450F08D912FBC9D7BDD4B26681E6D7C939827DC48", "checksum": "b217f26eae6d450570ee295b0d604663" }, "oracle": { - "label": "oracle", - "contract_id": 30090, - "address": "secret12pfmer5e35ekup9r4cvdm6zzql7fwudzsnc7m7", - "code_hash": "10912DA31D27B8B6AAB3AED4A9B9A2F0BAB120C87156FCDDA3CC9F7DD0DAD8B7", + "label": "oracle-OBIoWzXH", + "contract_id": "30157", + "address": "secret1hdwj0hyaukxyhd6msehpxndsgg9xujz9wh7ml0", + "code_hash": "F280D855FEF99EE9D6594086C897EB9AD76469C898FBC945A673C38405C975F4", "checksum": "31c3ff776e85627bf77c00787a94a68b" }, "silk": { @@ -20,10 +20,10 @@ "code_hash": "35F5DB2BC5CD56815D10C7A567D6827BECCB8EAF45BC3FA016930C4A8209EA69" }, "shade": { - "label": "shade", + "label": "shade-kDFYsowA", "contract_id": 30067, - "address": "", - "code_hash": "" + "address": "secret19wpwzyd7km3q4qkc4x80zz7fk5e3arxpmgwqs6", + "code_hash": "35F5DB2BC5CD56815D10C7A567D6827BECCB8EAF45BC3FA016930C4A8209EA69" }, "sscrt": { "label": "sSCRT", diff --git a/contracts/mint/README.md b/contracts/mint/README.md index fe03c2906..adfbd92f4 100644 --- a/contracts/mint/README.md +++ b/contracts/mint/README.md @@ -168,6 +168,8 @@ In the msg field of a snip20 send command you must send a base64 encoded json li {"minimum_expected_amount": "Uint128", "mint_type": { "mint_silk": { } } } ``` +The currently supported mint types are ```mint_silk``` and ```mint_shade``` + ## Contract Type used in many of the admin commands ```json diff --git a/contracts/mint/src/contract.rs b/contracts/mint/src/contract.rs index a38dba70e..ae82e47ce 100644 --- a/contracts/mint/src/contract.rs +++ b/contracts/mint/src/contract.rs @@ -14,6 +14,7 @@ use shade_protocol::{ }; use shade_protocol::generic_response::ResponseStatus; use shade_protocol::mint::{SnipMsgHook, MintType}; +use std::convert::TryFrom; // TODO: add remove asset // TODO: add spacepad padding @@ -30,6 +31,7 @@ pub fn init( Some(admin) => { admin } }, silk: msg.silk, + shade: msg.shade, oracle: msg.oracle, activated: true, }; @@ -66,8 +68,9 @@ pub fn handle( HandleMsg::UpdateConfig { owner, silk, + shade, oracle - } => try_update_config(deps, env, owner, silk, oracle), + } => try_update_config(deps, env, owner, silk, shade, oracle), HandleMsg::RegisterAsset { contract, } => try_register_asset(deps, &env, contract, None), @@ -117,6 +120,7 @@ pub fn try_migrate( let init_msg = InitMsg { admin: Option::from(config_read.owner), silk: config_read.silk, + shade: config_read.shade, oracle: config_read.oracle, initial_assets: Some(initial_assets) }; @@ -134,6 +138,7 @@ pub fn try_update_config( env: Env, owner: Option, silk: Option, + shade: Option, oracle: Option, ) -> StdResult { if !authorized(deps, &env, AllowedAccess::Admin)? { @@ -149,6 +154,9 @@ pub fn try_update_config( if let Some(silk) = silk { state.silk = silk; } + if let Some(shade) = shade { + state.shade = shade; + } if let Some(oracle) = oracle { state.oracle = oracle; } @@ -275,25 +283,26 @@ pub fn try_burn( // Get mint command let amount_to_mint: Uint128; + let mint_response: StdResult<(CosmosMsg, Uint128)>; if let Some(msg) = msg { let mint_msg: SnipMsgHook = from_binary(&msg)?; - match mint_msg.mint_type { - MintType::MintSilk {} => { - match mint_silk_with_asset(deps, &env, from, amount, mint_msg.minimum_expected_amount) { - Ok(tuple) => { - let (cosmos_msg, amount_returned) = tuple; - messages.push(cosmos_msg); - amount_to_mint = amount_returned; - } - Err(err) => { return Err(err) } - } - } + mint_response = match mint_msg.mint_type { + MintType::MintSilk {} => mint_with_asset(deps, &env, TargetCoin::Silk, from, amount, mint_msg.minimum_expected_amount), + MintType::MintShade {} => mint_with_asset(deps, &env, TargetCoin::Shade, from, amount, mint_msg.minimum_expected_amount) } } else { return Err(StdError::generic_err("data cannot be empty")) } - + // Handle response + match mint_response { + Ok(tuple) => { + let (cosmos_msg, amount_returned) = tuple; + messages.push(cosmos_msg); + amount_to_mint = amount_returned; + } + Err(err) => { return Err(err) } + } Ok(HandleResponse { messages, @@ -333,12 +342,36 @@ fn authorized( return Ok(true) } -fn calculate_mint(x: Uint128, y: Uint128, a: u32, b: u32) -> Uint128 { - // x = value * 10**18 - // y = value * 10**a - // ( x * y ) / ( 10**(18 - ( a - b ) ) ) - let exponent = (18 as i32 + a as i32 - b as i32) as u32; - x.multiply_ratio(y, 10u128.pow(exponent)) +fn calculate_mint(in_price: Uint128, target_price: Uint128, in_amount: Uint128, in_decimals: u32, target_decimals: u32) -> Uint128 { + // Math must only be made in integers + // in_decimals = x + // target_decimals = y + // in_price = p1 * 10^18 + // target_price = p2 * 10^18 + // in_amount = a1 * 10^x + // return = a2 * 10^y + + // (a1 * 10^x) * (p1 * 10^18) = (a2 * 10^y) * (p2 * 10^18) + + // (p1 * 10^18) + // (a1 * 10^x) * -------------- = (a2 * 10^y) + // (p2 * 10^18) + + let in_total = in_amount.multiply_ratio(in_price, target_price); + + // in_total * 10^(y - x) = (a2 * 10^y) + let difference: i32 = target_decimals as i32 - in_decimals as i32; + + // To avoid a mess of different types doing math + if difference < 0 { + in_total.multiply_ratio(1u128, 10u128.pow(u32::try_from(difference.abs()).unwrap())) + } + else if difference > 0 { + Uint128(in_total.u128() * 10u128.pow(u32::try_from(difference).unwrap())) + } + else { + in_total + } } fn register_receive ( @@ -357,9 +390,15 @@ fn register_receive ( cosmos_msg } -fn mint_silk_with_asset( +enum TargetCoin { + Silk, + Shade, +} + +fn mint_with_asset( deps: &mut Extern, env: &Env, + target: TargetCoin, sender: HumanAddr, amount: Uint128, minimum_expected_amount: Uint128, @@ -373,20 +412,29 @@ fn mint_silk_with_asset( None => return Err(StdError::NotFound { kind: env.message.sender.to_string(), backtrace: None }), } - // Returned value is x * 10**18 - let token_value = call_oracle(&deps, "SCRT".to_string())?; + // Query the coin values + let (in_price, target_price) = match target { + TargetCoin::Silk => (call_oracle(&deps, "SCRT".to_string())?, Uint128(10u128.pow(18))), + TargetCoin::Shade => (call_oracle(&deps, "SCRT".to_string())?, call_oracle(&deps, "SHD".to_string())?) + }; + + // Get the target coin information + let config = config_read(&deps.storage).load()?; + + let target_coin = match target { + TargetCoin::Silk => config.silk, + TargetCoin::Shade => config.shade + }; // Load the decimal information for both coins - let config = config_read(&deps.storage).load()?; - let send_decimals = token_info_query(&deps.querier, 1, asset_contract.code_hash, - asset_contract.address)?.decimals as u32; - let silk_decimals = token_info_query(&deps.querier, 1, - config.silk.code_hash.clone(), - config.silk.address.clone())?.decimals as u32; + let in_decimals = token_info_query(&deps.querier, 1, asset_contract.code_hash, + asset_contract.address)?.decimals as u32; + let target_decimals = token_info_query(&deps.querier, 1, + target_coin.code_hash.clone(), + target_coin.address.clone())?.decimals as u32; - // ( ( token_value * 10**18 ) * ( amount * 10**send_decimals ) ) / ( 10**(18 - ( send_decimals - silk-decimals ) ) ) // This will calculate the total mind value - let amount_to_mint = calculate_mint(token_value, amount, send_decimals, silk_decimals); + let amount_to_mint = calculate_mint(in_price, target_price, amount, in_decimals, target_decimals); // If minimum amount is greater then ignore the process if minimum_expected_amount > amount_to_mint { @@ -394,8 +442,8 @@ fn mint_silk_with_asset( } let mint_msg = mint_msg(sender, amount_to_mint, None, - 256, config.silk.code_hash, - config.silk.address)?; + 256, target_coin.code_hash, + target_coin.address)?; // Set burned amount let mut mut_assets = assets_w(&mut deps.storage); @@ -464,11 +512,12 @@ mod tests { } } - fn dummy_init(admin: String, silk: Contract, oracle: Contract) -> Extern { + fn dummy_init(admin: String, silk: Contract, shade: Contract, oracle: Contract) -> Extern { let mut deps = mock_dependencies(20, &[]); let msg = InitMsg { admin: None, silk, + shade, oracle, initial_assets: None }; @@ -484,6 +533,7 @@ mod tests { let msg = InitMsg { admin: None, silk: create_contract("", ""), + shade: create_contract("", ""), oracle: create_contract("", ""), initial_assets: None }; @@ -497,8 +547,9 @@ mod tests { #[test] fn config_update() { let silk_contract = create_contract("silk_contract", "silk_hash"); + let shade_contract = create_contract("shade_contract", "shade_hash"); let oracle_contract = create_contract("oracle_contract", "oracle_hash"); - let mut deps = dummy_init("admin".to_string(), silk_contract, oracle_contract); + let mut deps = dummy_init("admin".to_string(), silk_contract, shade_contract, oracle_contract); // Check config is properly updated let res = query(&deps, QueryMsg::GetConfig {}).unwrap(); @@ -521,6 +572,7 @@ mod tests { let msg = HandleMsg::UpdateConfig { owner: None, silk: Option::from(new_silk_contract), + shade: None, oracle: Option::from(new_oracle_contract), }; let _res = handle(&mut deps, user_env, msg); @@ -544,6 +596,7 @@ mod tests { #[test] fn user_register_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -571,6 +624,7 @@ mod tests { #[test] fn admin_register_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -594,6 +648,7 @@ mod tests { #[test] fn duplicate_register_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -620,6 +675,7 @@ mod tests { #[test] fn user_update_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -649,6 +705,7 @@ mod tests { #[test] fn admin_update_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -682,6 +739,7 @@ mod tests { #[test] fn nonexisting_update_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -711,6 +769,7 @@ mod tests { #[test] fn receiving_an_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -750,6 +809,7 @@ mod tests { #[test] fn receiving_an_asset_from_non_supported_asset() { let mut deps = dummy_init("admin".to_string(), + create_contract("", ""), create_contract("", ""), create_contract("", "")); @@ -786,21 +846,35 @@ mod tests { // In this example the "sent" value is 1 with 6 decimal places // The mint value will be 1 with 3 decimal places let price = Uint128(1_000_000_000_000_000_000); - let sent_value = Uint128(1_000_000); + let in_amount = Uint128(1_000_000); let expected_value = Uint128(1_000); - let value = calculate_mint(price, sent_value, 6, 3); + let value = calculate_mint(price, price, in_amount, 6, 3); assert_eq!(value, expected_value); } #[test] - fn mint_algorithm_complex() { + fn mint_algorithm_complex_1() { // In this example the "sent" value is 1.8 with 6 decimal places // The mint value will be 3.6 with 12 decimal places - let price = Uint128(2_000_000_000_000_000_000); - let sent_value = Uint128(1_800_000); + let in_price = Uint128(2_000_000_000_000_000_000); + let target_price = Uint128(1_000_000_000_000_000_000); + let in_amount = Uint128(1_800_000); let expected_value = Uint128(3_600_000_000_000); - let value = calculate_mint(price, sent_value, 6, 12); + let value = calculate_mint(in_price, target_price, in_amount, 6, 12); + + assert_eq!(value, expected_value); + } + + #[test] + fn mint_algorithm_complex_2() { + // In amount is 50.000 valued at 20 + // target price is 100$ with 6 decimals + let in_price = Uint128(20_000_000_000_000_000_000); + let target_price = Uint128(100_000_000_000_000_000_000); + let in_amount = Uint128(50_000); + let expected_value = Uint128(10_000_000); + let value = calculate_mint(in_price, target_price, in_amount, 3, 6); assert_eq!(value, expected_value); } diff --git a/contracts/mock_band/src/contract.rs b/contracts/mock_band/src/contract.rs index da8c19858..f2993ff27 100644 --- a/contracts/mock_band/src/contract.rs +++ b/contracts/mock_band/src/contract.rs @@ -47,7 +47,7 @@ pub fn query( QueryMsg::GetReferenceData { base_symbol: _, quote_symbol: _ } => to_binary(&ReferenceData { // data from ETH - rate: Uint128(3050262500000000000000), + rate: Uint128(1_000_000_000_000_000_000), last_updated_base: 1628544285u64, last_updated_quote: 3377610u64 }), diff --git a/packages/shade_protocol/src/mint.rs b/packages/shade_protocol/src/mint.rs index ca6923d80..af30dcbbd 100644 --- a/packages/shade_protocol/src/mint.rs +++ b/packages/shade_protocol/src/mint.rs @@ -9,6 +9,7 @@ use crate::msg_traits::{Init, Handle, Query}; pub struct MintConfig { pub owner: HumanAddr, pub silk: Contract, + pub shade: Contract, pub oracle: Contract, pub activated: bool, } @@ -24,6 +25,7 @@ pub struct BurnableAsset { pub struct InitMsg { pub admin: Option, pub silk: Contract, + pub shade: Contract, pub oracle: Contract, pub initial_assets: Option>, } @@ -41,6 +43,7 @@ pub enum HandleMsg { UpdateConfig { owner: Option, silk: Option, + shade: Option, oracle: Option, }, RegisterAsset { @@ -69,7 +72,8 @@ pub struct SnipMsgHook { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum MintType { - MintSilk {} + MintSilk {}, + MintShade {} } impl Handle<'_> for HandleMsg{}