Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
root: true,
// This tells ESLint to load the config from the package `eslint-config-custom`
extends: ["custom"],
settings: {
next: {
rootDir: ["apps/*/"],
},
},
};
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# next.js
.next/
out/
build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# turbo
.turbo

.env
coverage.json
typechain
typechain-types
cache
artifacts
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
# starklane
# Starklane

The Starklane NFT Bridge: seamless transfer of NFTs between ETH L1 & Starknet L2. Smart contracts, user-friendly interface, secure & efficient solution. Experience the future of NFT ownership today

# Quickstart

## Install dependencies

`yarn`

## Build all packages

`yarn build`
175 changes: 175 additions & 0 deletions apps/blockchain/contracts/starknet/bridge.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: MIT

%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.uint256 import Uint256, uint256_unsigned_div_rem
from starkware.starknet.common.syscalls import get_caller_address
from starkware.cairo.common.math import assert_not_zero
from starkware.cairo.common.alloc import alloc
from openzeppelin.access.ownable.library import Ownable
from starkware.starknet.common.syscalls import get_contract_address

@contract_interface
namespace IUniversalDeployerContract {
func deployContract(
classHash: felt, salt: felt, unique: felt, calldata_len: felt, calldata: felt*
) -> (address: felt) {
}
}

@contract_interface
namespace IDefaultToken {
func permissionedMint(to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt) {
}
}

@event
func collection_created(address: felt) {
}

@storage_var
func _l1_to_l2_addresses(l1_address: felt) -> (l1_address: felt) {
}

@storage_var
func _contract_salt() -> (salt: felt) {
}

@storage_var
func _token_class_hash() -> (res: felt) {
}

@storage_var
func _udc_contract() -> (res: felt) {
}

@constructor
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
owner: felt, class_hash: felt, initial_salt: felt, udc_contract: felt
) {
Ownable.initializer(owner);
_token_class_hash.write(class_hash);
_contract_salt.write(initial_salt);
_udc_contract.write(udc_contract);
return ();
}

@external
func handle_message{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
l1_contract_address: felt,
to: felt,
token_id: Uint256,
data_len: felt,
data: felt*,
name: felt,
symbol: felt,
token_uri: felt,
) -> (contract_address: felt) {
alloc_locals;

let (contract_address) = _l1_to_l2_addresses.read(l1_contract_address);
if (contract_address == 0) {
let (deployed_contract_address) = deploy_new_contract(l1_contract_address, name, symbol);
mint(
contract_address=deployed_contract_address,
token_id=token_id,
to=to,
token_uri=token_uri,
);
return (contract_address=deployed_contract_address);
} else {
mint(contract_address=contract_address, token_id=token_id, to=to, token_uri=token_uri);
return (contract_address=contract_address);
}
}

func deploy_new_contract{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
l1_contract_address: felt, name: felt, symbol: felt
) -> (contract_address: felt) {
alloc_locals;

let (bridge_contract_address) = get_contract_address();

let (message_payload: felt*) = alloc();

assert message_payload[0] = bridge_contract_address;
assert message_payload[1] = name;
assert message_payload[2] = symbol;

let (token_class_hash) = _token_class_hash.read();
let (udc_contract_address) = _udc_contract.read();
let (salt) = _contract_salt.read();
let new_salt = salt + 1;

let (deployed_contract_address) = IUniversalDeployerContract.deployContract(
contract_address=udc_contract_address,
classHash=token_class_hash,
salt=new_salt,
unique=0,
calldata_len=3,
calldata=message_payload,
);

_contract_salt.write(new_salt);
_l1_to_l2_addresses.write(l1_contract_address, deployed_contract_address);

collection_created.emit(address=deployed_contract_address);
return (contract_address=deployed_contract_address);
}

func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
contract_address: felt, token_id: Uint256, to: felt, token_uri: felt
) {
alloc_locals;
let (data: felt*) = alloc();

IDefaultToken.permissionedMint(
contract_address=contract_address,
to=to,
tokenId=token_id,
data_len=0,
data=data,
tokenURI=token_uri,
);

return ();
}

@external
func set_salt{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(salt: felt) {
Ownable.assert_only_owner();
_contract_salt.write(salt);
return ();
}

@external
func set_udc_contract{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
udc_contract: felt
) {
Ownable.assert_only_owner();
_udc_contract.write(udc_contract);
return ();
}

@view
func get_token_class_hash{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
res: felt
) {
let (res) = _token_class_hash.read();
return (res=res);
}

@view
func get_salt{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (salt: felt) {
let (salt) = _contract_salt.read();
return (salt=salt);
}

@view
func get_l2_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
l1_address: felt
) -> (l2_address: felt) {
let (l2_address) = _l1_to_l2_addresses.read(l1_address);
return (l2_address,);
}
142 changes: 142 additions & 0 deletions apps/blockchain/contracts/starknet/default_token.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: MIT

%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.uint256 import Uint256

from openzeppelin.token.erc721.library import ERC721
from openzeppelin.introspection.erc165.library import ERC165
from openzeppelin.access.ownable.library import Ownable

@constructor
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
owner: felt, name: felt, symbol: felt
) {
ERC721.initializer(name, symbol);
Ownable.initializer(owner);
return ();
}

//
// Getters
//

@view
func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
interfaceId: felt
) -> (success: felt) {
return ERC165.supports_interface(interfaceId);
}

@view
func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {
return ERC721.name();
}

@view
func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {
return ERC721.symbol();
}

@view
func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> (
balance: Uint256
) {
return ERC721.balance_of(owner);
}

@view
func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
token_id: Uint256
) -> (owner: felt) {
return ERC721.owner_of(token_id);
}

@view
func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
token_id: Uint256
) -> (approved: felt) {
return ERC721.get_approved(token_id);
}

@view
func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
owner: felt, operator: felt
) -> (isApproved: felt) {
let (isApproved) = ERC721.is_approved_for_all(owner, operator);
return (isApproved=isApproved);
}

@view
func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
tokenId: Uint256
) -> (tokenURI: felt) {
let (tokenURI) = ERC721.token_uri(tokenId);
return (tokenURI=tokenURI);
}

@view
func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {
return Ownable.owner();
}

//
// Externals
//

@external
func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
to: felt, tokenId: Uint256
) {
ERC721.approve(to, tokenId);
return ();
}

@external
func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
operator: felt, approved: felt
) {
ERC721.set_approval_for_all(operator, approved);
return ();
}

@external
func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
from_: felt, to: felt, tokenId: Uint256
) {
ERC721.transfer_from(from_, to, tokenId);
return ();
}

@external
func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*
) {
ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);
return ();
}

@external
func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
newOwner: felt
) {
Ownable.transfer_ownership(newOwner);
return ();
}

@external
func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
Ownable.renounce_ownership();
return ();
}

@external
func permissionedMint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt
) {
Ownable.assert_only_owner();
ERC721._safe_mint(to, tokenId, data_len, data);
ERC721._set_token_uri(tokenId, tokenURI);
return ();
}
9 changes: 9 additions & 0 deletions apps/blockchain/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "@shardlabs/starknet-hardhat-plugin";

const config: HardhatUserConfig = {
solidity: "0.8.17",
};

export default config;
Loading