-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
220 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# Code generated by scarb DO NOT EDIT. | ||
version = 1 | ||
|
||
[[package]] | ||
name = "cartridge_vrf" | ||
version = "0.1.0" | ||
dependencies = [ | ||
"openzeppelin", | ||
"openzeppelin_testing", | ||
"openzeppelin_utils", | ||
"snforge_std", | ||
"stark_vrf", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_access", | ||
"openzeppelin_account", | ||
"openzeppelin_governance", | ||
"openzeppelin_introspection", | ||
"openzeppelin_presets", | ||
"openzeppelin_security", | ||
"openzeppelin_token", | ||
"openzeppelin_upgrades", | ||
"openzeppelin_utils", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_access" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_introspection", | ||
"openzeppelin_utils", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_account" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_introspection", | ||
"openzeppelin_token", | ||
"openzeppelin_utils", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_governance" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_access", | ||
"openzeppelin_introspection", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_introspection" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
|
||
[[package]] | ||
name = "openzeppelin_presets" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_access", | ||
"openzeppelin_account", | ||
"openzeppelin_introspection", | ||
"openzeppelin_token", | ||
"openzeppelin_upgrades", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_security" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
|
||
[[package]] | ||
name = "openzeppelin_testing" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"snforge_std", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_token" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
dependencies = [ | ||
"openzeppelin_account", | ||
"openzeppelin_governance", | ||
"openzeppelin_introspection", | ||
] | ||
|
||
[[package]] | ||
name = "openzeppelin_upgrades" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
|
||
[[package]] | ||
name = "openzeppelin_utils" | ||
version = "0.15.0-rc.0" | ||
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?rev=a13bae3#a13bae3390a7114a8c14c0352c6898eff5f4f5d7" | ||
|
||
[[package]] | ||
name = "snforge_std" | ||
version = "0.26.0" | ||
source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.26.0#50eb589db65e113efe4f09241feb59b574228c7e" | ||
|
||
[[package]] | ||
name = "stark_vrf" | ||
version = "0.1.0" | ||
source = "git+https://github.com/dojoengine/stark-vrf.git#96d6d2a88b1ef46c4a285d0ccc334237205edae3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,3 @@ | ||
# VRF for Cartridge Controller with paymaster | ||
## Documentation | ||
|
||
Randomness is requested by calling `vrf_provider.request_random` with: | ||
- caller : the contract that will call consume_random | ||
- source : one of this 2 options : | ||
|
||
**Source::Nonce(address)** : | ||
- each request_random will generate a unique seed using a nonce by address (nonce is increased after each call) | ||
- (its recommanded to use wallet address to avoid nonce collisions) | ||
|
||
**Source::Salt(salt)** : | ||
- you have to provider you own salt | ||
- using same salt will generate same seed = same randomness | ||
|
||
|
||
## How it works | ||
|
||
caller send multicall : | ||
|
||
``` | ||
[ | ||
vrf_provider.request_random(game_contract.address, Source::Nonce(wallet_address)), | ||
game_contract.you_function_consuming_randomness(...params) | ||
] | ||
``` | ||
|
||
Cartridge backend receive the tx, | ||
retrieve seed using vrf_provider.get_next_seed( caller ), | ||
compute proof for seed | ||
and inject calls to sandwitch caller in a multicall : | ||
|
||
``` | ||
[ | ||
vrf_provider.submit_random( seed, proof), | ||
controller.outside_execution([ | ||
vrf_provider.request_random(game_contract.address, Source::Nonce(wallet_address)), | ||
game_contract.you_function_consuming_randomness(...params) | ||
]) | ||
vrf_provider.assert_consumed( seed ), | ||
] | ||
``` | ||
|
||
# Notes | ||
|
||
- caller must be a Cartridge Controller | ||
- Randomness must be consume | ||
- Randomness can only be consumed once | ||
- Tx (submit_random / user calls / assert_consumed) is executed atomically by Cartridge backend | ||
- Sumbitted randomness only last for the tx duration | ||
- It's not possible to request_random in a tx and consume_random in another tx | ||
- User cannot probe randomness | ||
[Cartridge Controller Documentation](https://docs.cartridge.gg/controller/overview) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,80 @@ | ||
|
||
import { StarkVRF } from "stark-vrf-wasm"; | ||
import { AccountInterface, Call, CallData} from "starknet"; | ||
import { AccountInterface, BlockTag, Call, CallData, hash, selector } from "starknet"; | ||
|
||
enum Source { | ||
Nonce = 0x0, | ||
Salt = 0x1, | ||
} | ||
|
||
export const buildVrfCalls = async ({ | ||
account, | ||
call, | ||
vrfProviderAddress, | ||
vrfProviderSecret, | ||
}: { | ||
account: AccountInterface; | ||
call: Call; | ||
vrfProviderAddress: string; | ||
vrfProviderSecret?: string; | ||
}): Promise<Call[]> => { | ||
|
||
const [seed] = await account.callContract({ | ||
account, | ||
call, | ||
vrfProviderAddress, | ||
vrfProviderSecret, | ||
}: { | ||
account: AccountInterface; | ||
call: Call; | ||
vrfProviderAddress: string; | ||
vrfProviderSecret?: string; | ||
}): Promise<Call[]> => { | ||
// fn request_random(caller: ContractAddress, source: Source) -> felt252; | ||
const requestRandomCall: Call = { | ||
contractAddress: vrfProviderAddress, | ||
entrypoint: "request_random", | ||
calldata: [call.contractAddress, Source.Nonce, account.address], | ||
}; | ||
|
||
let submitRandomCall = undefined; | ||
let assertConsumedCall = undefined; | ||
|
||
if (vrfProviderSecret) { | ||
const chainId = await account.getChainId(); | ||
|
||
const nonceStorageSlot = hash.computePedersenHash( | ||
selector.getSelectorFromName("VrfProvider_nonces"), | ||
account.address, | ||
); | ||
|
||
const nonce = await account.getStorageAt(vrfProviderAddress, nonceStorageSlot, BlockTag.pending); | ||
const seed = hash.computePoseidonHashOnElements([nonce, call.contractAddress, chainId]); | ||
console.log(chainId); | ||
console.log(nonceStorageSlot); | ||
console.log(nonce); | ||
console.log(seed); | ||
|
||
// const vrf = StarkVRF.new(vrfProviderSecret); | ||
|
||
const vrf = (await import("stark-vrf-wasm")).StarkVRF.new(vrfProviderSecret); | ||
const proof = vrf.prove(vrfProviderSecret, seed); | ||
const sqrt_ratio_hint = vrf.hashToSqrtRatioHint(seed); | ||
|
||
// fn submit_random( seed: felt252, proof: Proof); | ||
submitRandomCall = { | ||
contractAddress: vrfProviderAddress, | ||
entrypoint: "get_next_seed", | ||
calldata: [account.address], | ||
}); | ||
|
||
const requestRandomCall: Call = { | ||
entrypoint: "submit_random", | ||
calldata: CallData.compile([seed, proof, sqrt_ratio_hint]), | ||
}; | ||
|
||
// fn assert_consumed( seed: felt252,); | ||
assertConsumedCall = { | ||
contractAddress: vrfProviderAddress, | ||
entrypoint: "request_random", | ||
calldata: [], | ||
entrypoint: "assert_consumed", | ||
calldata: [seed], | ||
}; | ||
|
||
let submitRandomCall: Call|undefined = undefined; | ||
let assertConsumedCall: Call|undefined = undefined; | ||
|
||
if (vrfProviderSecret) { | ||
const vrf = StarkVRF.new(vrfProviderSecret); | ||
const proof = vrf.prove(vrfProviderSecret, seed); | ||
const sqrt_ratio_hint = vrf.hashToSqrtRatioHint(seed); | ||
|
||
// fn submit_random( seed: felt252, proof: Proof); | ||
submitRandomCall = { | ||
contractAddress: vrfProviderAddress, | ||
entrypoint: "submit_random", | ||
calldata: CallData.compile([seed, proof, sqrt_ratio_hint]), | ||
}; | ||
|
||
// fn assert_consumed( seed: felt252,); | ||
assertConsumedCall = { | ||
contractAddress: vrfProviderAddress, | ||
entrypoint: "assert_consumed", | ||
calldata: [seed], | ||
}; | ||
} | ||
|
||
let calls = []; | ||
if (vrfProviderSecret) { | ||
calls.push(submitRandomCall as Call); | ||
} | ||
|
||
calls.push(requestRandomCall); | ||
calls.push(call); | ||
|
||
if (vrfProviderSecret) { | ||
calls.push(assertConsumedCall as Call); | ||
} | ||
|
||
console.log("calls", calls); | ||
return calls; | ||
}; | ||
} | ||
|
||
let calls = []; | ||
if (vrfProviderSecret) { | ||
calls.push(submitRandomCall as Call); | ||
} | ||
|
||
calls.push(requestRandomCall); | ||
calls.push(call); | ||
|
||
if (vrfProviderSecret) { | ||
calls.push(assertConsumedCall as Call); | ||
} | ||
|
||
console.log("calls", calls); | ||
return calls; | ||
}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.