Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename claim --> gift #46

Merged
merged 13 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The goal of this protocol is to allow sending tokens to a recipient without know

## High level Flow

1. The sender creates a key pair locally called **claim_key**.
1. The sender creates a key pair locally called **gift_key**.
2. The sender deposits the tokens to be transferred, along with a small amount of fee token (ETH or STK) to cover the claim transaction, to the factory. The sender also specifies the **public key** as an identifier.
3. The factory deploys an escrow account to which the gift amount is transferred along with the fee amount.
4. The sender shares the **private key** with the recipient over an external channel such as text or email.
Expand All @@ -14,7 +14,7 @@ As the fee should be larger than the claiming transaction cost, there might be a

## Claiming

Claim can be done in two ways:
Claiming can be done in two ways:

### Through the account

Expand All @@ -35,7 +35,7 @@ If the gift has already been claimed, this allows the sender to redeem the lefto
This section outlines all the operations that the factory is allowed to perform.
As we use OpenZeppelin's Ownable component, this factory has an owner.

### Get Dust
### Claim Dust

The factory has a function allowing it to claim the dust left on an account. This action can only be done after a claim has been performed. This can also be used to recover any excess tokens a user may have sent to the account.

Expand All @@ -49,9 +49,9 @@ The factory can be upgraded to a newer version, allowing it to potentially recov
The upgrade cannot be done immediately and must go through a waiting period of 7 days. There is then a window of 7 days to perform the upgrade.
It is important to note that through an upgrade, the ownership of the factory and its upgradeability can both be revoked.

## Gift account address calculation
## Escrow account address calculation

To compute the address of the escrow account, you can either call `get_claim_address()` with the relevant arguments. Or you can do it off-chain using, for example, starknetJS.
To compute the address of the escrow account, you can either call `get_escrow_address()` with the relevant arguments. Or you can do it off-chain using, for example, starknetJS.
The parameters are as follow:

- Salt: 0
Expand Down
18 changes: 9 additions & 9 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ dependencies = [
"alexandria_math",
]

[[package]]
name = "argent_gifting"
version = "0.1.0"
dependencies = [
"alexandria_math",
"openzeppelin",
"snforge_std",
]

[[package]]
name = "openzeppelin"
version = "0.13.0"
Expand All @@ -43,12 +52,3 @@ source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.13.0#97
name = "snforge_std"
version = "0.24.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.24.0#95e9fb09cb91b3c05295915179ee1b55bf923653"

[[package]]
name = "starknet_gifting"
version = "0.1.0"
dependencies = [
"alexandria_math",
"openzeppelin",
"snforge_std",
]
2 changes: 1 addition & 1 deletion Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "starknet_gifting"
name = "argent_gifting"
version = "0.1.0"
edition = "2023_11"

Expand Down
72 changes: 36 additions & 36 deletions lib/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import {
LegacyStarknetKeyPair,
StarknetSignature,
calculateClaimAddress,
calculateEscrowAddress,
deployer,
ethAddress,
manager,
Expand Down Expand Up @@ -69,36 +69,36 @@ export interface AccountConstructorArguments {
gift_amount: bigint;
fee_token: string;
fee_amount: bigint;
claim_pubkey: bigint;
gift_pubkey: bigint;
}

export interface Claim extends AccountConstructorArguments {
export interface Gift extends AccountConstructorArguments {
factory: string;
class_hash: string;
}

export function buildCallDataClaim(claim: Claim) {
export function buildGiftCallData(gift: Gift) {
return {
...claim,
gift_amount: uint256.bnToUint256(claim.gift_amount),
...gift,
gift_amount: uint256.bnToUint256(gift.gift_amount),
};
}

export async function signExternalClaim(signParams: {
claim: Claim;
gift: Gift;
receiver: string;
claimPrivateKey: string;
giftPrivateKey: string;
dustReceiver?: string;
forceClaimAddress?: string;
forceEscrowAddress?: string;
}): Promise<StarknetSignature> {
const giftSigner = new LegacyStarknetKeyPair(signParams.claimPrivateKey);
const giftSigner = new LegacyStarknetKeyPair(signParams.giftPrivateKey);
const claimExternalData = await getClaimExternalData({
receiver: signParams.receiver,
dustReceiver: signParams.dustReceiver,
});
const stringArray = (await giftSigner.signMessage(
claimExternalData,
signParams.forceClaimAddress || calculateClaimAddress(signParams.claim),
signParams.forceEscrowAddress || calculateEscrowAddress(signParams.gift),
)) as string[];
if (stringArray.length !== 2) {
throw new Error("Invalid signature");
Expand All @@ -107,29 +107,29 @@ export async function signExternalClaim(signParams: {
}

export async function claimExternal(args: {
claim: Claim;
gift: Gift;
receiver: string;
claimPrivateKey: string;
giftPrivateKey: string;
dustReceiver?: string;
overrides?: { account?: Account };
details?: UniversalDetails;
}): Promise<TransactionReceipt> {
const account = args.overrides?.account || deployer;
const signature = await signExternalClaim({
claim: args.claim,
gift: args.gift,
receiver: args.receiver,
claimPrivateKey: args.claimPrivateKey,
giftPrivateKey: args.giftPrivateKey,
dustReceiver: args.dustReceiver,
});

const claimExternalCallData = CallData.compile([
buildCallDataClaim(args.claim),
buildGiftCallData(args.gift),
args.receiver,
args.dustReceiver || "0x0",
signature,
]);
const response = await account.execute(
executeActionOnAccount("claim_external", calculateClaimAddress(args.claim), claimExternalCallData),
executeActionOnAccount("claim_external", calculateEscrowAddress(args.gift), claimExternalCallData),
undefined,
{ ...args.details },
);
Expand All @@ -145,19 +145,19 @@ function executeActionOnAccount(functionName: string, accountAddress: string, ar
}

export async function claimInternal(args: {
claim: Claim;
gift: Gift;
receiver: string;
claimPrivateKey: string;
overrides?: { claimAccountAddress?: string; callToAddress?: string };
giftPrivateKey: string;
overrides?: { EscrowAccountAddress?: string; callToAddress?: string };
details?: UniversalDetails;
}): Promise<TransactionReceipt> {
const claimAddress = args.overrides?.claimAccountAddress || calculateClaimAddress(args.claim);
const claimAccount = getClaimAccount(args.claim, args.claimPrivateKey, claimAddress);
const response = await claimAccount.execute(
const escrowAddress = args.overrides?.EscrowAccountAddress || calculateEscrowAddress(args.gift);
const escrowAccount = getEscrowAccount(args.gift, args.giftPrivateKey, escrowAddress);
const response = await escrowAccount.execute(
[
{
contractAddress: args.overrides?.callToAddress ?? claimAddress,
calldata: [buildCallDataClaim(args.claim), args.receiver],
contractAddress: args.overrides?.callToAddress ?? escrowAddress,
calldata: [buildGiftCallData(args.gift), args.receiver],
entrypoint: "claim_internal",
},
],
Expand All @@ -167,24 +167,24 @@ export async function claimInternal(args: {
return manager.waitForTransaction(response.transaction_hash);
}

export async function cancelGift(args: { claim: Claim; senderAccount?: Account }): Promise<TransactionReceipt> {
const cancelCallData = CallData.compile([buildCallDataClaim(args.claim)]);
export async function cancelGift(args: { gift: Gift; senderAccount?: Account }): Promise<TransactionReceipt> {
const cancelCallData = CallData.compile([buildGiftCallData(args.gift)]);
const account = args.senderAccount || deployer;
const response = await account.execute(
executeActionOnAccount("cancel", calculateClaimAddress(args.claim), cancelCallData),
executeActionOnAccount("cancel", calculateEscrowAddress(args.gift), cancelCallData),
);
return manager.waitForTransaction(response.transaction_hash);
}

export async function getDust(args: {
claim: Claim;
export async function claimDust(args: {
gift: Gift;
receiver: string;
factoryOwner?: Account;
}): Promise<TransactionReceipt> {
const getDustCallData = CallData.compile([buildCallDataClaim(args.claim), args.receiver]);
const claimDustCallData = CallData.compile([buildGiftCallData(args.gift), args.receiver]);
const account = args.factoryOwner || deployer;
const response = await account.execute(
executeActionOnAccount("get_dust", calculateClaimAddress(args.claim), getDustCallData),
executeActionOnAccount("claim_dust", calculateEscrowAddress(args.gift), claimDustCallData),
);
return manager.waitForTransaction(response.transaction_hash);
}
Expand All @@ -202,12 +202,12 @@ export const randomReceiver = (): string => {
return `0x${encode.buf2hex(ec.starkCurve.utils.randomPrivateKey())}`;
};

export function getClaimAccount(claim: Claim, claimPrivateKey: string, forceClaimAddress?: string): Account {
export function getEscrowAccount(gift: Gift, giftPrivateKey: string, forceEscrowAddress?: string): Account {
return new Account(
manager,
forceClaimAddress || num.toHex(calculateClaimAddress(claim)),
claimPrivateKey,
forceEscrowAddress || num.toHex(calculateEscrowAddress(gift)),
giftPrivateKey,
undefined,
useTxv3(claim.fee_token) ? RPC.ETransactionVersion.V3 : RPC.ETransactionVersion.V2,
useTxv3(gift.fee_token) ? RPC.ETransactionVersion.V3 : RPC.ETransactionVersion.V2,
);
}
4 changes: 2 additions & 2 deletions lib/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import {
import { deployer } from "./accounts";
import { WithDevnet } from "./devnet";

export const contractsFolder = "./target/release/starknet_gifting_";
export const fixturesFolder = "./tests-integration/fixtures/starknet_gifting_";
export const contractsFolder = "./target/release/argent_gifting_";
export const fixturesFolder = "./tests-integration/fixtures/argent_gifting_";

export const WithContracts = <T extends ReturnType<typeof WithDevnet>>(Base: T) =>
class extends Base {
Expand Down
Loading
Loading