Skip to content

Commit

Permalink
feat(ark-contracts): add nft contract
Browse files Browse the repository at this point in the history
  • Loading branch information
remiroyc committed Dec 7, 2023
1 parent 4508ab2 commit 40542a4
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 20 deletions.
6 changes: 6 additions & 0 deletions crates/ark-contracts/common/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ version = 1
name = "ark_common"
version = "0.1.0"
dependencies = [
"openzeppelin",
"snforge_std",
]

[[package]]
name = "openzeppelin"
version = "0.8.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.8.0#c23e8e96de60e6e3159b1ff8591a1187269c0eb7"

[[package]]
name = "snforge_std"
version = "0.1.0"
Expand Down
5 changes: 5 additions & 0 deletions crates/ark-contracts/common/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ version = "0.1.0"
[dependencies]
starknet = "2.3.1"
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.9.1" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.0" }

[lib]

[[target.starknet-contract]]
sierra = true
casm = true
4 changes: 4 additions & 0 deletions crates/ark-contracts/common/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ mod crypto {
mod hash;
mod signer;
}

mod tokens {
mod nft;
}
63 changes: 63 additions & 0 deletions crates/ark-contracts/common/src/tokens/nft.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use starknet::ContractAddress;

#[starknet::interface]
trait IFreeMint<T> {
fn mint(ref self: T, recipient: ContractAddress, token_id: u256);
}

#[starknet::contract]
mod FreeMintNFT {
use super::IFreeMint;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::token::erc721::ERC721Component;
use starknet::ContractAddress;

component!(path: ERC721Component, storage: erc721, event: ERC721Event);
component!(path: SRC5Component, storage: src5, event: SRC5Event);

// ERC721
#[abi(embed_v0)]
impl ERC721Impl = ERC721Component::ERC721Impl<ContractState>;
#[abi(embed_v0)]
impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl<ContractState>;
#[abi(embed_v0)]
impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl<ContractState>;
#[abi(embed_v0)]
impl ERC721MetadataCamelOnly =
ERC721Component::ERC721MetadataCamelOnlyImpl<ContractState>;
impl ERC721InternalImpl = ERC721Component::InternalImpl<ContractState>;

// SRC5
#[abi(embed_v0)]
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
erc721: ERC721Component::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC721Event: ERC721Component::Event,
#[flat]
SRC5Event: SRC5Component::Event
}

#[constructor]
fn constructor(ref self: ContractState, name: felt252, symbol: felt252) {
self.erc721.initializer(name, symbol);
}

#[external(v0)]
impl ImplFreeMint of IFreeMint<ContractState> {
fn mint(ref self: ContractState, recipient: ContractAddress, token_id: u256) {
self.erc721._mint(recipient, token_id);
// self.erc721._set_token_uri(token_id, 0);
}
}
}
2 changes: 1 addition & 1 deletion crates/ark-contracts/common/tests/test_hash.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ fn test_create_listing() {
let poseidon_hash = serialized_hash(order_hash);
poseidon_hash.print();
let signer = sign_mock(poseidon_hash, Option::None);
}
}
1 change: 1 addition & 0 deletions crates/ark-contracts/starknet/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ version = 1
name = "ark_common"
version = "0.1.0"
dependencies = [
"openzeppelin",
"snforge_std",
]

Expand Down
12 changes: 7 additions & 5 deletions crates/ark-contracts/starknet/src/executor.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ mod executor {
use ark_starknet::appchain_messaging::{
IAppchainMessagingDispatcher, IAppchainMessagingDispatcherTrait,
};
use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};

use openzeppelin::token::{
erc721::interface::{IERC721, IERC721Dispatcher, IERC721DispatcherTrait},
erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}
};

#[storage]
struct Storage {
Expand Down Expand Up @@ -61,7 +65,6 @@ mod executor {

#[external(v0)]
impl ExecutorImpl of IExecutor<ContractState> {

fn get_test_address(ref self: ContractState) -> ContractAddress {
self.test_address.read()
}
Expand Down Expand Up @@ -120,7 +123,6 @@ mod executor {
}

fn execute_order(ref self: ContractState, execution_info: ExecutionInfo) {

self.test_address.write(starknet::get_caller_address());

// assert(
Expand All @@ -132,8 +134,8 @@ mod executor {
contract_address: self.eth_contract_address.read()
};

//let nft_contract = IERCDispatcher { contract_address: execution_info.token_address };
//nft_contract.transfer_from(execution_info.maker_address, execution_info.taker_address, execution_info.token_id);
let nft_contract = IERC721Dispatcher { contract_address: execution_info.token_address };
// nft_contract.transfer_from(execution_info.fulfiller_address, execution_info.offerer_address, execution_info.token_id);

// self._transfer_royalties(execution_info, eth_contract);

Expand Down
1 change: 1 addition & 0 deletions crates/ark-contracts/starknet/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ mod executor;

//mod tests;


45 changes: 39 additions & 6 deletions packages/core/examples/fulfillListing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
* submitting a listing order and cancelling it.
*/

import { RpcProvider, shortString } from "starknet";
import { Account, cairo, CallData, RpcProvider, shortString } from "starknet";

import { createAccount } from "../src/actions/account/account";
import { createListing, fulfillListing } from "../src/actions/order";
import { getOrderHash, getOrderStatus } from "../src/actions/read";
import { EVERAI_NFT_ADDRESS } from "../src/constants";
import { ListingV1 } from "../src/types";

// Initialize the RPC provider with the ArkChain node URL
const provider = new RpcProvider({
const arkchainProvider = new RpcProvider({
nodeUrl: "http://0.0.0.0:7777"
});

const katanaProvider = new RpcProvider({
nodeUrl: "http://0.0.0.0:5050"
});

/**
* Creates a listing on the blockchain using provided order details.
*
Expand All @@ -24,13 +29,41 @@ const provider = new RpcProvider({
(async (provider: RpcProvider) => {
// Create a new account for the listing using the provider
const { account: listing_account } = await createAccount(provider);
console.log("Created account: ", listing_account.address);

const katana0 = {
privateKey: "0x1800000000300000180000000000030000000000003006001800006600",
publicKey:
"0x2b191c2f3ecf685a91af7cf72a43e7b90e2e41220175de5c4f7498981b10053",
accountAddress:
"0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
};

// Get katana0 account
const katana0Account = new Account(
katanaProvider,
katana0.accountAddress,
katana0.privateKey
);

const tokenId = 3;

await katana0Account.execute({
contractAddress: EVERAI_NFT_ADDRESS,
entrypoint: "mint",
calldata: CallData.compile({
recipient: katana0Account.address,
token_id: cairo.uint256(tokenId)
})
});

console.log("Minted everai token: ", tokenId);

// Define the order details
let order: ListingV1 = {
brokerId: 123, // The broker ID
tokenAddress:
"0x01435498bf393da86b4733b9264a86b58a42b31f8d8b8ba309593e5c17847672", // The token address
tokenId: 16, // The ID of the token
tokenAddress: EVERAI_NFT_ADDRESS,
tokenId: tokenId, // The ID of the token
startAmount: 600000000000000000 // The starting amount for the order
};

Expand Down Expand Up @@ -73,4 +106,4 @@ const provider = new RpcProvider({
provider
);
console.log("orderStatus", shortString.decodeShortString(orderStatusAfter));
})(provider);
})(arkchainProvider);
5 changes: 3 additions & 2 deletions packages/core/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const ORDER_BOOK_ADDRESS =
export const ORDER_BOOK_ADDRESS =
process.env.ORDERBOOK_CONTRACT ||
"0x46ddb3a4b23520a9944ae5213f27660115d5dd24ac47fb95c9f3a799bcdd1ca";

export { ORDER_BOOK_ADDRESS };
export const EVERAI_NFT_ADDRESS =
"0x7a39fd46a05526515cb577a52b45a14818585424b1eff7bbe76601369e580fe";
35 changes: 35 additions & 0 deletions scripts/deployer/contracts/freemint-erc721.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as sn from "starknet";

import * as common from "./common.js";

export async function declareDeploy(
common_artifacts_path,
account,
provider,
name,
symbol
) {
const artifacts = common.load_artifacts(
common_artifacts_path,
"ark_common_FreeMintNFT"
);

const contractCallData = new sn.CallData(artifacts.sierra.abi);
const contractConstructor = contractCallData.compile("constructor", {
name,
symbol
});

const deployR = await account.declareAndDeploy({
contract: artifacts.sierra,
casm: artifacts.casm,
constructorCalldata: contractConstructor,
salt: 0x7777
});

return new sn.Contract(
artifacts.sierra.abi,
deployR.deploy.contract_address,
provider
);
}
30 changes: 24 additions & 6 deletions scripts/deployer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as sn from "starknet";

import * as appmsg from "./contracts/appchain_messaging.js";
import * as executor from "./contracts/executor.js";
import * as erc721 from "./contracts/freemint-erc721.js";
import * as orderbook from "./contracts/orderbook.js";

const STARKGATE =
Expand All @@ -28,6 +29,7 @@ const solis_account0 = new sn.Account(solis, account0, privkey0);
const sn_artifacts_path = "../../crates/ark-contracts/starknet/target/dev/";
const arkchain_artifacts_path =
"../../crates/ark-contracts/arkchain/target/dev/";
const common_artifacts_path = "../../crates/ark-contracts/common/target/dev/";

let orderbook_contract = await orderbook.declareDeploy(
arkchain_artifacts_path,
Expand All @@ -37,7 +39,20 @@ let orderbook_contract = await orderbook.declareDeploy(
admin: account0
}
);
console.log("orderbook (ark)", orderbook_contract.address);

console.log("💠 ARKCHAIN CONTRACTS");
console.log("- orderbook: ", orderbook_contract.address);

let nft = await erc721.declareDeploy(
common_artifacts_path,
katana_account0,
katana,
"Everai",
"Everai"
);

console.log("\n💅 STARKNET CONTRACTS");
console.log("- everai nft: ", nft.address);

let appmsg_contract = await appmsg.declareDeploy(
sn_artifacts_path,
Expand All @@ -49,6 +64,8 @@ let appmsg_contract = await appmsg.declareDeploy(
}
);

console.log("- appmsg: ", appmsg_contract.address);

let executor_contract = await executor.declareDeploy(
sn_artifacts_path,
katana_account0,
Expand All @@ -60,17 +77,18 @@ let executor_contract = await executor.declareDeploy(
messaging_address: appmsg_contract.address
}
);
console.log("executor (sn)", executor_contract.address);
console.log("- executor: ", executor_contract.address);

let calldata = sn.CallData.compile({
value: executor_contract.address
});
console.log("---");

await solis_account0.execute({
contractAddress: orderbook_contract.address,
entrypoint: "update_starknet_executor_address",
calldata: calldata
calldata: sn.CallData.compile({
value: executor_contract.address
})
});
console.log("Updated executor address in orderbook");

// TODO: Solis requires the address of the orderbook + the executor address,
// So if the code changes for any of those contracts, the address must be pre-computed
Expand Down

0 comments on commit 40542a4

Please sign in to comment.