Skip to content

Commit

Permalink
feat: gasless request-owner-update
Browse files Browse the repository at this point in the history
  • Loading branch information
efstajas committed Jul 24, 2023
1 parent e34e3bc commit 4bfda17
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 84 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ PINATA_SDK_SECRET=string
TENDERLY_USER=string
TENDERLY_PROJECT=string
TENDERLY_ACCESS_SECRET=string
GELATO_API_KEY=string
57 changes: 53 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
},
"dependencies": {
"@efstajas/svelte-stored-writable": "^0.2.0",
"@gelatonetwork/relay-sdk": "^4.0.0",
"@octokit/rest": "^19.0.7",
"@pinata/sdk": "^1.1.26",
"@safe-global/safe-apps-provider": "^0.16.0",
Expand Down
4 changes: 2 additions & 2 deletions src/lib/stores/wallet/wallet.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const GOERLI_RPC_URL = 'https://goerli.infura.io/v3/f88a1229d473471bbf94d168401b
const { SUPPORTED_CHAINS } = Utils.Network;
// TODO: change this after development.
const DEFAULT_NETWORK: Network = {
chainId: 1,
name: 'homestead',
chainId: 5,
name: 'goerli',
};

const injected = injectedWallets();
Expand Down
7 changes: 4 additions & 3 deletions src/lib/utils/get-drips-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,9 @@ export const networkConfigs: { [chainId: number]: NetworkConfig } = isTest()
* Get the networkConfig for the current network.
* @returns The networkConfig for the current network.
*/
export function getNetworkConfig() {
const { network } = get(wallet);
export function getNetworkConfig(chainId = get(wallet).network.chainId): NetworkConfig {
const config = networkConfigs[chainId];
assert(config, `No network config found for chainId ${chainId}`);

return networkConfigs[network.chainId];
return config;
}
69 changes: 69 additions & 0 deletions src/routes/api/gasless/call/repo-owner-update/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { z } from 'zod';
import type { RequestHandler } from './$types';
import { error } from '@sveltejs/kit';
import { ethers, utils } from 'ethers';
import { getNetworkConfig } from '$lib/utils/get-drips-clients';
import unreachable from '$lib/utils/unreachable';
import { GelatoRelay, type SponsoredCallRequest } from '@gelatonetwork/relay-sdk';
import { GELATO_API_KEY } from '$env/static/private';
import assert from '$lib/utils/assert';

const payloadSchema = z.object({
forge: z.number(),
projectName: z.string(),
chainId: z.number(),
});

const REPO_DRIVER_ABI = `[
{
"inputs": [
{ "internalType": "enum Forge", "name": "forge", "type": "uint8" },
{ "internalType": "bytes", "name": "name", "type": "bytes" }
],
"name": "requestUpdateOwner",
"outputs": [{ "internalType": "uint256", "name": "accountId", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
}
]`;

export const POST: RequestHandler = async ({ request }) => {
let payload: z.infer<typeof payloadSchema>;

try {
const body = await request.text();
payload = payloadSchema.parse(JSON.parse(body));
} catch {
throw error(400, 'Invalid payload');
}

const { forge, projectName, chainId } = payload;

assert(chainId === 5, 'Only Goerli is supported for now');

const repoDriverAddress = getNetworkConfig(chainId)?.REPO_DRIVER ?? unreachable();

// TODO: Use our own provider
const contract = new ethers.Contract(
repoDriverAddress,
REPO_DRIVER_ABI,
ethers.getDefaultProvider({ chainId, name: 'goerli' }),
);

const tx = await contract.populateTransaction.requestUpdateOwner(
forge,
utils.toUtf8Bytes(projectName),
);

const relayRequest: SponsoredCallRequest = {
chainId: chainId,
target: tx.to ?? unreachable(),
data: tx.data ?? unreachable(),
};

const relay = new GelatoRelay();

const relayResponse = await relay.sponsoredCall(relayRequest, GELATO_API_KEY);

return new Response(JSON.stringify(relayResponse));
};
7 changes: 7 additions & 0 deletions src/routes/api/gasless/track/[taskId]/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
const taskStatus = await fetch(`https://api.gelato.digital/tasks/status/${params.taskId}`);

return new Response(await taskStatus.text());
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,66 @@
function verify() {
dispatch('await', {
promise: () =>
new Promise<void>((resolve, reject) => {
const { address } = $walletStore;
assert(address);
promise: async () => {
const { address } = $walletStore;
assert(address);
const addressInMaintainers = $context.maintainerSplits.items[address];
const maintainersListEmpty = Object.keys($context.maintainerSplits.items).length === 0;
const addressInMaintainers = $context.maintainerSplits.items[address];
const maintainersListEmpty = Object.keys($context.maintainerSplits.items).length === 0;
if (!addressInMaintainers && maintainersListEmpty) {
$context.maintainerSplits.items = {
[address]: ethAddressItem(address),
};
if (!addressInMaintainers && maintainersListEmpty) {
$context.maintainerSplits.items = {
[address]: ethAddressItem(address),
};
$context.maintainerSplits.selected = [address];
$context.maintainerSplits.selected = [address];
$context.maintainerSplits.percentages = {
[address]: 100,
};
}
$context.maintainerSplits.percentages = {
[address]: 100,
};
}
try {
const { username, repoName } = GitProjectService.deconstructUrl($context.gitUrl);
const { forge, username, repoName } = GitProjectService.deconstructUrl($context.gitUrl);
resolve(
github
.getFundingJson(
username,
repoName,
dripsJsonTemplate(
$walletStore.address ?? unreachable(),
$walletStore.network.name
? $walletStore.network.name === 'homestead'
? 'ethereum'
: $walletStore.network.name
: unreachable(),
),
)
.then(() => {
$context.linkedToRepo = true;
}),
);
} catch (error) {
reject('FUNDING.json not found.');
}
}),
try {
await github.getFundingJson(
username,
repoName,
dripsJsonTemplate(
$walletStore.address ?? unreachable(),
$walletStore.network.name
? $walletStore.network.name === 'homestead'
? 'ethereum'
: $walletStore.network.name
: unreachable(),
),
);
$context.linkedToRepo = true;
} catch (error) {
throw new Error('FUNDING.json not found.');
}
try {
// Kick off repo owner update using gasless TX
await fetch('/api/gasless/call/repo-owner-update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
forge,
projectName: `${username}/${repoName}`,
chainId: $walletStore.network.chainId,
}),
});
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
throw new Error('Failed to gasless-call repo-owner-update');
}
},
message: 'Verifying...',
subtitle:
'We’re scanning your git project’s main branch for a FUNDING.json file with your Ethereum address.',
Expand Down
Loading

0 comments on commit 4bfda17

Please sign in to comment.