Skip to content

Commit

Permalink
Integrate contracts (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonatan-Chaverri authored Jan 22, 2025
1 parent 7f465c9 commit c41986a
Show file tree
Hide file tree
Showing 43 changed files with 3,851 additions and 168 deletions.
3 changes: 3 additions & 0 deletions apps/snfoundry/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
PRIVATE_KEY_SEPOLIA=
RPC_URL_SEPOLIA=https://starknet-sepolia.public.blastapi.io/rpc/v0_7
ACCOUNT_ADDRESS_SEPOLIA=

# IPFS
TOKEN_METADATA_URL="ipfs://test/{id}.json"
73 changes: 73 additions & 0 deletions apps/snfoundry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CofiBlocks Contracts

## Deployment Guide

Follow these steps to deploy the CofiBlocks contracts on the StarkNet network.

### 1. Configure the `.env` file

Set the following environment variables in your `.env` file with the details of a prefunded wallet. This wallet will act as the admin address:

- **`PRIVATE_KEY_SEPOLIA`** – The private key of the admin wallet.
- **`ACCOUNT_ADDRESS_SEPOLIA`** – The address of the admin wallet.
- **`TOKEN_METADATA_URL`** – The IPFS URL to serve as the token metadata.

The URL should follow the format: `ipfs://<CID>/{id}.json`, where `{id}` will be dynamically replaced with the actual token ID by clients when fetching metadata.

**Example:**
```
ipfs://bafybeihevtihdmcjkdh6sjdtkbdjnngbfdlr3tjk2dfmvd3demdm57o3va/{id}.json
```
For token ID `1`, the resulting URL will be:
```
ipfs://bafybeihevtihdmcjkdh6sjdtkbdjnngbfdlr3tjk2dfmvd3demdm57o3va/1.json
```

### 2. Install dependencies

Run the following command to install project dependencies:
```bash
bun i
```

### 3. Deploy the contracts

To deploy the contracts on the Sepolia testnet, run:
```bash
bun deploy:sepolia
```

This command will:
- Deploy both the **CofiCollections** and **Marketplace** contracts.
- Set the **Marketplace** contract as the minter in the **CofiCollection** contract.
- Set the `base_uri` in the **CofiCollection** contract using the `TOKEN_METADATA_URL` value from the `.env` file.

### 4. Retrieve deployed contract addresses

Once the deployment is complete, the contract addresses will be available in:
- The terminal output.
- The file located at: `deployments/sepolia_latest.json`.


## Testing
To test the contracts, follow these steps.

1. Go to contracts folder
```bash
cd contracts
```

2. Run test command
```bash
scarb test
```

## Note
When updating the contracts, you need to update them in the web app too. To do that follow this steps

1. Go to page https://scaffold-stark-demo.vercel.app/configure
2. Copy/paste the contract address in the Address field. Use this valid names: CofiCollection, Marketplace.
3. Click on download Contract file. It will give you a json file with the contract abi and contract address.
4. Update the file https://github.com/Vagabonds-Labs/cofiblocks/blob/main/apps/web/src/contracts/configExternalContracts.ts
with the new data (just copy/paste the contract metadata in the corresponding field without affecting other contracts metadata).
5. Do the same for Marketplace contract.
2 changes: 1 addition & 1 deletion apps/snfoundry/contracts/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version = 1

[[package]]
name = "contracts"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"openzeppelin",
"snforge_std",
Expand Down
10 changes: 9 additions & 1 deletion apps/snfoundry/contracts/Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "contracts"
edition = "2023_11"
version = "0.2.0"
version = "0.3.0"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

Expand All @@ -13,9 +13,17 @@ starknet = "2.8.2"
[dev-dependencies]
assert_macros = "2.8.2"

[scripts]
test = "snforge test"

[[target.starknet-contract]]
casm = true
sierra = true

[[tool.snforge.fork]]
name = "SEPOLIA_LATEST"
url = "https://starknet-sepolia.public.blastapi.io/rpc/v0_7"
block_id.tag = "latest"

[tool.fmt]
sort-module-level-items = true
9 changes: 9 additions & 0 deletions apps/snfoundry/contracts/src/cofi_collection.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ pub trait ICofiCollection<TContractState> {

/// Unpauses all token transfers.
fn unpause(ref self: TContractState);

// Update minter after deployment
fn set_minter(ref self: TContractState, minter: ContractAddress);
}

#[starknet::contract]
Expand Down Expand Up @@ -375,5 +378,11 @@ mod CofiCollection {
self.accesscontrol.assert_only_role(URI_SETTER_ROLE);
self.erc1155._set_base_uri(base_uri);
}

#[external(v0)]
fn set_minter(ref self: ContractState, minter: ContractAddress) {
self.accesscontrol.assert_only_role(DEFAULT_ADMIN_ROLE);
self.accesscontrol._grant_role(MINTER_ROLE, minter);
}
}
}
2 changes: 2 additions & 0 deletions apps/snfoundry/contracts/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod cofi_collection;
mod marketplace;

#[cfg(test)]
mod test {
mod test_cofi_collection;
mod test_marketplace;
}

mod mock_contracts {
Expand Down
31 changes: 22 additions & 9 deletions apps/snfoundry/contracts/src/marketplace.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ pub trait IMarketplace<ContractState> {
fn buy_products(ref self: ContractState, token_ids: Span<u256>, token_amount: Span<u256>);
fn create_product(
ref self: ContractState, initial_stock: u256, price: u256, data: Span<felt252>
);
fn create_products(ref self: ContractState, initial_stock: Span<u256>, price: Span<u256>);
) -> u256;
fn create_products(
ref self: ContractState, initial_stock: Span<u256>, price: Span<u256>
) -> Span<u256>;
fn delete_product(ref self: ContractState, token_id: u256);
fn delete_products(ref self: ContractState, token_ids: Span<u256>);
fn claim_balance(self: @ContractState, producer: ContractAddress) -> u256;
fn claim(ref self: ContractState);
}

Expand Down Expand Up @@ -207,6 +210,10 @@ mod Marketplace {
strk_token_dispatcher.balance_of(get_caller_address()) >= total_price,
'insufficient funds'
);
assert(
strk_token_dispatcher.allowance(buyer, contract_address) >= total_price,
'insufficient allowance'
);
strk_token_dispatcher.transfer_from(buyer, contract_address, total_price);

// Transfer the nft products
Expand Down Expand Up @@ -317,7 +324,7 @@ mod Marketplace {
/// * `data` - Additional context or metadata for the token transfer process
fn create_product(
ref self: ContractState, initial_stock: u256, price: u256, data: Span<felt252>
) {
) -> u256 {
self.accesscontrol.assert_only_role(PRODUCER);
let token_id = self.current_token_id.read();
let cofi_collection = ICofiCollectionDispatcher {
Expand All @@ -326,13 +333,15 @@ mod Marketplace {
cofi_collection.mint(get_contract_address(), token_id, initial_stock, data);

let producer = get_caller_address();
self.seller_products.write(token_id, producer);

self.current_token_id.write(token_id + 1);
self.initialize_product(token_id, producer, initial_stock, price);
token_id
}

fn create_products(ref self: ContractState, initial_stock: Span<u256>, price: Span<u256>) {
fn create_products(
ref self: ContractState, initial_stock: Span<u256>, price: Span<u256>
) -> Span<u256> {
assert(initial_stock.len() == price.len(), 'wrong len of arrays');
self.accesscontrol.assert_only_role(PRODUCER);
let producer = get_caller_address();
Expand Down Expand Up @@ -372,6 +381,7 @@ mod Marketplace {
);
token_idx += 1;
};
token_ids.span()
}

fn delete_product(ref self: ContractState, token_id: u256) {
Expand Down Expand Up @@ -418,9 +428,14 @@ mod Marketplace {
self.update_stock(token_id, 0);
cofi_collection.burn(token_holder, token_id, amount_tokens);
self.emit(DeleteProduct { token_id });
token_idx += 1;
};
}

fn claim_balance(self: @ContractState, producer: ContractAddress) -> u256 {
self.claim_balances.read(producer)
}

fn claim(ref self: ContractState) {
self.accesscontrol.assert_only_role(PRODUCER);
let producer = get_caller_address();
Expand All @@ -429,9 +444,7 @@ mod Marketplace {
let strk_token_dispatcher = IERC20Dispatcher {
contract_address: contract_address_const::<STRK_TOKEN_ADDRESS>()
};
strk_token_dispatcher.approve(producer, claim_balance);
let transfer = strk_token_dispatcher
.transfer_from(get_contract_address(), producer, claim_balance);
let transfer = strk_token_dispatcher.transfer(producer, claim_balance);
assert(transfer, 'Error claiming');

self.claim_balances.write(producer, 0);
Expand All @@ -448,7 +461,7 @@ mod Marketplace {
price: u256
) {
//let product = Product { stock, price };
//self.seller_products.entry(producer).write(token_id);
self.seller_products.write(token_id, producer);
self.listed_product_stock.write(token_id, stock);
self.listed_product_price.write(token_id, price);
self.emit(CreateProduct { token_id, initial_stock: stock });
Expand Down
Loading

0 comments on commit c41986a

Please sign in to comment.