Skip to content

Commit

Permalink
supabase: sendtag checkout updates
Browse files Browse the repository at this point in the history
- confirm_tags to use transfers to sendtag checkout contract
- update tag receipt activity
- updates tests
  • Loading branch information
0xBigBoss committed Jul 20, 2024
1 parent c166009 commit 9c65f26
Show file tree
Hide file tree
Showing 14 changed files with 470 additions and 187 deletions.
16 changes: 16 additions & 0 deletions .snaplet/snaplet-client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,16 @@ type Override = {
event_id?: string;
};
}
sendtag_checkout_contracts?: {
name?: string;
fields?: {
id?: string;
address?: string;
chain_id?: string;
created_at?: string;
updated_at?: string;
};
}
tag_receipts?: {
name?: string;
fields?: {
Expand Down Expand Up @@ -715,6 +725,12 @@ export interface Fingerprint {
logIdx?: FingerprintNumberField;
abiIdx?: FingerprintNumberField;
}
sendtagCheckoutContracts?: {
id?: FingerprintNumberField;
chainId?: FingerprintNumberField;
createdAt?: FingerprintDateField;
updatedAt?: FingerprintDateField;
}
tagReceipts?: {
id?: FingerprintNumberField;
createdAt?: FingerprintDateField;
Expand Down
8 changes: 8 additions & 0 deletions .snaplet/snaplet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,13 @@ interface Table_public_send_token_transfers {
log_idx: number;
abi_idx: number;
}
interface Table_public_sendtag_checkout_contracts {
id: number;
address: string;
chain_id: number;
created_at: string | null;
updated_at: string | null;
}
interface Table_auth_sessions {
id: string;
user_id: string;
Expand Down Expand Up @@ -619,6 +626,7 @@ interface Schema_public {
send_liquidity_pools: Table_public_send_liquidity_pools;
send_revenues_safe_receives: Table_public_send_revenues_safe_receives;
send_token_transfers: Table_public_send_token_transfers;
sendtag_checkout_contracts: Table_public_sendtag_checkout_contracts;
tag_receipts: Table_public_tag_receipts;
tag_reservations: Table_public_tag_reservations;
tags: Table_public_tags;
Expand Down
24 changes: 23 additions & 1 deletion packages/contracts/script/anvil-add-send-merkle-drop-fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import 'zx/globals'
import { supabaseAdmin } from 'app/utils/supabase/admin'
import type { Database } from '@my/supabase/database.types'
import { createClient } from '@supabase/supabase-js'

if (!process.env.NEXT_PUBLIC_SUPABASE_URL) {
throw new Error(
'NEXT_PUBLIC_SUPABASE_URL is not set. Please update the root .env.local and restart the server.'
)
}
if (!process.env.SUPABASE_SERVICE_ROLE) {
throw new Error(
'SUPABASE_SERVICE_ROLE is not set. Please update the root .env.local and restart the server.'
)
}

const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL
const SUPABASE_SERVICE_ROLE = process.env.SUPABASE_SERVICE_ROLE

/**
* only meant to be used on the server side.
*/
const supabaseAdmin = createClient<Database>(SUPABASE_URL, SUPABASE_SERVICE_ROLE, {
auth: { persistSession: false },
})

$.verbose = true

Expand Down
48 changes: 46 additions & 2 deletions packages/contracts/script/anvil-add-sendtag-checkout-fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
import 'zx/globals'
import type { Database } from '@my/supabase/database.types'
import { createClient } from '@supabase/supabase-js'

if (!process.env.NEXT_PUBLIC_SUPABASE_URL) {
throw new Error(
'NEXT_PUBLIC_SUPABASE_URL is not set. Please update the root .env.local and restart the server.'
)
}
if (!process.env.SUPABASE_SERVICE_ROLE) {
throw new Error(
'SUPABASE_SERVICE_ROLE is not set. Please update the root .env.local and restart the server.'
)
}

const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL
const SUPABASE_SERVICE_ROLE = process.env.SUPABASE_SERVICE_ROLE

/**
* only meant to be used on the server side.
*/
const supabaseAdmin = createClient<Database>(SUPABASE_URL, SUPABASE_SERVICE_ROLE, {
auth: { persistSession: false },
})

$.verbose = true

/**
Expand All @@ -19,12 +43,32 @@ MULTISIG=${$.env.MULTISIG}\t\thttps://basescan.org/address/${$.env.MULTISIG}
TOKEN=${$.env.TOKEN}\t\thttps://basescan.org/address/${$.env.TOKEN}
`
)
await $`forge script ./script/DeploySendtagCheckout.s.sol:DeploySendtagCheckoutScript \
const contractAddress: string | undefined = await $`forge script ./script/DeploySendtagCheckout.s.sol:DeploySendtagCheckoutScript \
-vvvv \
--rpc-url ${RPC_URL} \
--sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--broadcast`
--broadcast`.then(
({ stdout }) => stdout.match(/contract SendtagCheckout (0x[a-fA-F0-9]{40})/)?.[1]
)

if (!contractAddress) {
console.error(chalk.red('Failed to deploy SendtagCheckout contract'))
process.exit(1)
}

console.log(chalk.blue(`SendtagCheckout contract deployed to ${contractAddress}`))
// add sendtag checkout contract to supabase
const { error } = await supabaseAdmin.from('sendtag_checkout_contracts').insert({
address: contractAddress.replace('0x', '\\x'),
chain_id: 845337,
})

if (error) {
console.error(chalk.red('Failed to add SendtagCheckout contract to supabase'))
console.error(error)
process.exit(1)
}

console.log(chalk.blue('Disable auto-mining...'))
await $`cast rpc --rpc-url ${RPC_URL} evm_setAutomine false`
Expand Down
24 changes: 24 additions & 0 deletions supabase/database-generated.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,30 @@ export type Database = {
}
Relationships: []
}
sendtag_checkout_contracts: {
Row: {
address: string
chain_id: number
created_at: string | null
id: number
updated_at: string | null
}
Insert: {
address: string
chain_id: number
created_at?: string | null
id?: number
updated_at?: string | null
}
Update: {
address?: string
chain_id?: number
created_at?: string | null
id?: number
updated_at?: string | null
}
Relationships: []
}
tag_receipts: {
Row: {
created_at: string | null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
set check_function_bodies = off;

create table sendtag_checkout_contracts (
id serial primary key,
address bytea not null,
chain_id integer not null,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);

insert into sendtag_checkout_contracts (address, chain_id) values (
'\x3936f906910C0f74b6d1536614068368B94CDa85', 8453
);

alter table sendtag_checkout_contracts enable row level security;

CREATE OR REPLACE FUNCTION public.confirm_tags(tag_names citext[], event_id text, referral_code_input text)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $function$
declare tag_owner_ids uuid [];

distinct_user_ids INT;

tag_owner_id uuid;

referrer_id uuid;

_event_id alias for $2;

checkout_contracts bytea [];
begin
-- Check if the tags exist and fetch their owners.
select array_agg(user_id) into tag_owner_ids
from public.tags
where name = any (tag_names)
and status = 'pending'::public.tag_status;

-- If any of the tags do not exist or are not in pending status, throw an error.
if array_length(tag_owner_ids, 1) <> array_length(tag_names, 1) then raise exception 'One or more tags do not exist or are not in pending status.';

end if;

-- Check if all tags belong to the same user
select count(distinct user_id) into distinct_user_ids
from unnest(tag_owner_ids) as user_id;

if distinct_user_ids <> 1 then raise exception 'Tags must belong to the same user.';

end if;

-- Fetch single user_id
select distinct user_id into tag_owner_id
from unnest(tag_owner_ids) as user_id;

if event_id is null
or event_id = '' then raise exception 'Receipt event ID is required for paid tags.';

end if;

-- Ensure we have sendtag_checkout_contracts
select array_agg(address) into checkout_contracts
from sendtag_checkout_contracts
limit 1;
if (checkout_contracts is null)
then raise exception 'Sendtag checkout contract not found.';
end if;

-- Ensure event_id matches the sender
if (
select count(distinct sat.f)
from public.send_account_transfers sat
join send_accounts sa on decode(substring(sa.address, 3), 'hex') = sat.f
where sat.event_id = _event_id
and sa.user_id = tag_owner_id
and sat.t = any(checkout_contracts)
) <> 1 then raise exception 'Receipt event ID does not match the sender';
end if;

-- save receipt event_id
insert into public.receipts (event_id, user_id) values (_event_id, tag_owner_id);

-- Associate the tags with the onchain event
insert into public.tag_receipts (tag_name, event_id)
select unnest(tag_names),
event_id;

-- Confirm the tags
update public.tags
set status = 'confirmed'::public.tag_status
where name = any (tag_names)
and status = 'pending'::public.tag_status;

-- Create referral code redemptions
if referral_code_input is not null
and referral_code_input <> '' then
SELECT id INTO referrer_id
FROM public.profiles
WHERE referral_code = referral_code_input;

if referrer_id is not null -- 'Referral code is not valid.'
and referrer_id <> tag_owner_id then -- Referrer cannot be the tag owner.
INSERT INTO public.referrals (referrer_id, referred_id, tag)
select referrer_id,
tag_owner_id,
unnest(tag_names);

end if;

end if;

end;

$function$
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
set check_function_bodies = off;

CREATE OR REPLACE FUNCTION public.tag_receipts_insert_activity_trigger()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
begin
delete from activity
where event_name = 'tag_receipt_usdc'
and event_id in (select event_id from NEW_TABLE);

insert into activity (event_name, event_id, from_user_id, to_user_id, data, created_at)
select
'tag_receipt_usdc',
NEW_TABLE.event_id,
t.user_id,
null,
json_build_object(
'log_addr',
sat.log_addr,
'block_num',
sat.block_num,
'tx_idx',
sat.tx_idx,
'log_idx',
sat.log_idx,
'tx_hash',
sat.tx_hash,
'tags',
array_agg(t.name),
'value',
-- cast v to text to avoid losing precision when converting to json when sending to clients
sat.v::text
),
current_timestamp
from NEW_TABLE
join tags t on t.name = NEW_TABLE.tag_name
join send_account_transfers sat ON NEW_TABLE.event_id = sat.event_id
group by t.user_id, NEW_TABLE.event_id, sat.event_id, sat.log_addr, sat.block_num, sat.tx_idx, sat.log_idx, sat.tx_hash, sat.v;

return NULL;
end;
$function$
;


Loading

0 comments on commit 9c65f26

Please sign in to comment.