Skip to content

Commit

Permalink
Merge pull request #47 from radixdlt/bugfix/new-non-fungible-resource…
Browse files Browse the repository at this point in the history
…-with-initial-supply

Bugfix: `CREATE_NON_FUNGIBLE_RESOURCE_WITH_INITIAL_SUPPLY`
  • Loading branch information
0xOmarA authored Mar 24, 2023
2 parents f94777a + a60ab58 commit 6795d42
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 28 deletions.
14 changes: 7 additions & 7 deletions cli-json-interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ radix-engine-toolkit = { path = "../radix-engine-toolkit" }
serde = "1.0.152"
serde_json = "1.0.93"

sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "transaction" }
radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
radix-engine-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "transaction" }
radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
radix-engine-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
hex = "0.4.3"

[[bin]]
Expand Down
14 changes: 7 additions & 7 deletions radix-engine-toolkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ schemars = { version = "0.8.11", features = ["preserve_order"] }
toolkit-derive = { path = "../toolkit-derive" }

# Scrypto dependencies required for the core-toolkit
sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "transaction" }
radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", optional = true }
radix-engine-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "transaction" }
radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", optional = true }
radix-engine-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }

# Hex is used for the internal hex encoding and decoding of values - serde_with::Hex is used for the
# hex representation during serialization.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub struct StaticallyValidateTransactionRequest {
/// The response from [`StaticallyValidateTransactionRequest`].
#[serializable]
#[serde(tag = "validity")]
#[derive(PartialEq, Eq)]
pub enum StaticallyValidateTransactionResponse {
Valid,
Invalid { error: String },
Expand Down
243 changes: 243 additions & 0 deletions radix-engine-toolkit/tests/statically_validate_transaction_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use native_transaction::builder::{ManifestBuilder, TransactionBuilder};
use native_transaction::ecdsa_secp256k1::EcdsaSecp256k1PrivateKey;
use native_transaction::manifest::{compile, decompile};
use native_transaction::model::{NotarizedTransaction, TransactionHeader};
use native_transaction::validation::ValidationConfig;
use radix_engine_common::ManifestSbor;
use radix_engine_constants::DEFAULT_COST_UNIT_LIMIT;
use radix_engine_toolkit::request::{
Handler, StaticallyValidateTransactionHandler, StaticallyValidateTransactionRequest,
StaticallyValidateTransactionResponse,
};
use scrypto::prelude::*;

#[test]
fn static_validation_of_simple_transfer_succeeds() {
// Arrange
let private_key1 = EcdsaSecp256k1PrivateKey::from_u64(1).unwrap();
let private_key2 = EcdsaSecp256k1PrivateKey::from_u64(2).unwrap();

let account1 = ComponentAddress::virtual_account_from_public_key(&private_key1.public_key());
let account2 = ComponentAddress::virtual_account_from_public_key(&private_key2.public_key());

let manifest = ManifestBuilder::new()
.lock_fee(account1, 10.into())
.withdraw_from_account(account1, RADIX_TOKEN, 1.into())
.call_method(
account2,
"deposit_batch",
manifest_args!(ManifestExpression::EntireWorktop),
)
.build();

let transaction = TransactionBuilder::new()
.header(header(0x0c, private_key1.public_key()))
.manifest(manifest)
.notarize(&private_key1)
.build();

// Act
test_inversion(&transaction);
let validation_result = statically_validate(&transaction);

// Assert
assert_eq!(
validation_result,
StaticallyValidateTransactionResponse::Valid
);
}

#[test]
fn static_validation_of_creating_a_simple_fungible_resource_succeeds() {
// Arrange
let private_key = EcdsaSecp256k1PrivateKey::from_u64(1).unwrap();
let account = ComponentAddress::virtual_account_from_public_key(&private_key.public_key());

let manifest = ManifestBuilder::new()
.lock_fee(account, 10.into())
.create_fungible_resource(
18,
BTreeMap::new(),
BTreeMap::<_, (_, AccessRule)>::new(),
None,
)
.build();

let transaction = TransactionBuilder::new()
.header(header(0x0c, private_key.public_key()))
.manifest(manifest)
.notarize(&private_key)
.build();

// Act
test_inversion(&transaction);
let validation_result = statically_validate(&transaction);

// Assert
assert_eq!(
validation_result,
StaticallyValidateTransactionResponse::Valid
);
}

#[test]
fn static_validation_of_creating_a_simple_non_fungible_resource_succeeds() {
// Arrange
let private_key = EcdsaSecp256k1PrivateKey::from_u64(1).unwrap();
let account = ComponentAddress::virtual_account_from_public_key(&private_key.public_key());

let manifest = ManifestBuilder::new()
.lock_fee(account, 10.into())
.create_non_fungible_resource(
NonFungibleIdType::Integer,
BTreeMap::new(),
BTreeMap::<_, (_, AccessRule)>::new(),
None::<BTreeMap<NonFungibleLocalId, EmptyStruct>>,
)
.build();

let transaction = TransactionBuilder::new()
.header(header(0x0c, private_key.public_key()))
.manifest(manifest)
.notarize(&private_key)
.build();

// Act
test_inversion(&transaction);
let validation_result = statically_validate(&transaction);

// Assert
assert_eq!(
validation_result,
StaticallyValidateTransactionResponse::Valid
);
}

#[test]
fn static_validation_of_creating_a_simple_non_fungible_resource_with_initial_supply_succeeds() {
// Arrange
let private_key = EcdsaSecp256k1PrivateKey::from_u64(1).unwrap();
let account = ComponentAddress::virtual_account_from_public_key(&private_key.public_key());

let manifest = ManifestBuilder::new()
.lock_fee(account, 10.into())
.create_non_fungible_resource(
NonFungibleIdType::Integer,
BTreeMap::new(),
BTreeMap::<_, (_, AccessRule)>::new(),
Some([(
NonFungibleLocalId::Integer(IntegerNonFungibleLocalId::new(1)),
EmptyStruct {},
)]),
)
.build();

let transaction = TransactionBuilder::new()
.header(header(0x0c, private_key.public_key()))
.manifest(manifest)
.notarize(&private_key)
.build();

// Act
test_inversion(&transaction);
let validation_result = statically_validate(&transaction);

// Assert
assert_eq!(
validation_result,
StaticallyValidateTransactionResponse::Valid
);
}

#[test]
fn static_validation_of_minting_non_fungible_tokens_succeeds() {
// Arrange
let private_key = EcdsaSecp256k1PrivateKey::from_u64(1).unwrap();
let account = ComponentAddress::virtual_account_from_public_key(&private_key.public_key());

let manifest = ManifestBuilder::new()
.lock_fee(account, 10.into())
.mint_non_fungible(
RADIX_TOKEN,
[(
NonFungibleLocalId::Integer(IntegerNonFungibleLocalId::new(1)),
EmptyStruct {},
)],
)
.build();

let transaction = TransactionBuilder::new()
.header(header(0x0c, private_key.public_key()))
.manifest(manifest)
.notarize(&private_key)
.build();

// Act
test_inversion(&transaction);
let validation_result = statically_validate(&transaction);

// Assert
assert_eq!(
validation_result,
StaticallyValidateTransactionResponse::Valid
);
}

fn header<P: Into<PublicKey>>(network_id: u8, notary_public_key: P) -> TransactionHeader {
TransactionHeader {
version: 0x01,
network_id,
start_epoch_inclusive: 10,
end_epoch_exclusive: 13,
nonce: 0x02,
notary_public_key: notary_public_key.into(),
notary_as_signatory: true,
cost_unit_limit: DEFAULT_COST_UNIT_LIMIT,
tip_percentage: 0,
}
}

fn test_inversion(transaction: &NotarizedTransaction) {
let passed_manifest = transaction.signed_intent.intent.manifest.clone();
let inverted_manifest = {
let network = radix_engine_toolkit::utils::network_definition_from_network_id(
transaction.signed_intent.intent.header.network_id,
);
let decompiled = decompile(&passed_manifest.instructions, &network).unwrap();
compile(&decompiled, &network, vec![]).unwrap()
};
assert_eq!(passed_manifest, inverted_manifest);
}

fn statically_validate(
transaction: &NotarizedTransaction,
) -> StaticallyValidateTransactionResponse {
let encoded_transaction = manifest_encode(&transaction).unwrap();
let request = StaticallyValidateTransactionRequest {
compiled_notarized_intent: encoded_transaction,
validation_config: ValidationConfig::default(
transaction.signed_intent.intent.header.network_id,
),
};
StaticallyValidateTransactionHandler::fulfill(request).unwrap()
}

#[derive(ScryptoSbor, NonFungibleData, ManifestSbor)]
struct EmptyStruct {}
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ CREATE_NON_FUNGIBLE_RESOURCE_WITH_INITIAL_SUPPLY
# a vault that they control. This behavior is permanent and can not be changed by anybody
# as the mutability is a `Enum("AccessRule::DenyAll")`.
#
# ┌ We Are customizing the "Withdraw" behavior of the resource
# │
# │ ┌ The resource may be withdrawn by anybody who has it
# │ │
# │ │ ┌ The withdraw behavior (the resource is withdrawable by
# │ │ │ by anybody who has the resource) is permanent and can't
# │ │ │ be changed in the future.
# │ │ │
# ┌ We Are customizing the "Withdraw" behavior of the resource
#
# │ ┌ The resource may be withdrawn by anybody who has it
# │ │
# │ │ ┌ The withdraw behavior (the resource is withdrawable by
# │ │ │ by anybody who has the resource) is permanent and can't
# │ │ │ be changed in the future.
# │ │ │
Enum("ResourceMethodAuthKey::Withdraw"), Tuple(Enum("AccessRule::AllowAll"), Enum("AccessRule::DenyAll")),
Enum("ResourceMethodAuthKey::Deposit"), Tuple(Enum("AccessRule::AllowAll"), Enum("AccessRule::DenyAll"))
)
Map<NonFungibleLocalId, Tuple>(
NonFungibleLocalId("${non_fungible_local_id}"),
Tuple("Hello World", Decimal("12"))
Tuple(Tuple("Hello World", Decimal("12")))
);

# Depositing the entirety of the initial supply of the newly created resource into our account
Expand Down
10 changes: 5 additions & 5 deletions schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ radix-engine-toolkit = { path = "../radix-engine-toolkit" }
serde = "1.0.152"
convert_case = "0.6.0"

sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f", package = "transaction" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-fac7a0c0f" }
sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }
scrypto_utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "utils" }
native_transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93", package = "transaction" }
radix-engine-constants = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "rcnet-v1-2b019f93" }

0 comments on commit 6795d42

Please sign in to comment.