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

refactor: spawn token process before we create repo #36

Merged
merged 2 commits into from
Nov 24, 2024
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
5 changes: 5 additions & 0 deletions .changeset/thirty-bats-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@protocol.land/sync': minor
---

attach empty process to new repo for token
85 changes: 75 additions & 10 deletions src/lib/aoHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import {
dryrun,
message,
result,
spawn,
} from '@permaweb/aoconnect';
import type { Tag } from 'arweave/node/lib/transaction';
import { getAddress } from './arweaveHelper';
import { getAddress, pollForTxBeingAvailable } from './arweaveHelper';
import { trackAmplitudeAnalyticsEvent } from './analytics';

const title = getTitle();
Expand Down Expand Up @@ -73,8 +74,8 @@ export async function getRepo(name: string) {
process: AOS_PROCESS_ID,
tags: getTags({
Action: 'Get-Repo-By-Name-Owner',
"Repo-Name": name,
"Owner-Address": address,
'Repo-Name': name,
'Owner-Address': address,
Fields: JSON.stringify([
'id',
'name',
Expand Down Expand Up @@ -129,7 +130,10 @@ export async function postRepo(
}
} else {
try {
const result = await newRepo(repoId, dataTxId);
const tokenProcessId = await spawnTokenProcess(title);

if (!tokenProcessId) throw '[ AO ] Failed to spawn token process';
const result = await newRepo(repoId, dataTxId, tokenProcessId);
await trackAmplitudeAnalyticsEvent(
'Repository',
'Successfully created a repo',
Expand All @@ -151,8 +155,13 @@ export async function postRepo(
}
}

async function newRepo(repoId: string, dataTxId: string) {
if (!title || !dataTxId) throw '[ AO ] No title or dataTx for new repo';
async function newRepo(
repoId: string,
dataTxId: string,
tokenProcessId: string
) {
if (!title || !dataTxId || !tokenProcessId)
throw '[ AO ] No title or dataTx or tokenProcessId for new repo';

const uploadStrategy =
process.env.STRATEGY === 'ARSEEDING' ? 'ARSEEDING' : 'DEFAULT';
Expand All @@ -165,8 +174,9 @@ async function newRepo(repoId: string, dataTxId: string) {
Id: repoId,
Name: title,
Description: description,
"Data-TxId": dataTxId,
"Upload-Strategy": uploadStrategy,
'Data-TxId': dataTxId,
'Upload-Strategy': uploadStrategy,
'Token-Process-Id': tokenProcessId,
}),
});

Expand All @@ -188,12 +198,67 @@ async function updateRepo(id: string, dataTxId: string) {
tags: getTags({
Action: 'Update-Repo-TxId',
Id: id,
"Data-TxId": dataTxId,
"Upload-Strategy": uploadStrategy,
'Data-TxId': dataTxId,
'Upload-Strategy': uploadStrategy,
}),
});

console.log(`[ AO ] Repo '${title}' with id '${id}' updated`);

return { id };
}

async function spawnTokenProcess(repoName: string) {
const aosDetails = await getAosDetails();
const tags = [
{ name: 'App-Name', value: 'aos' },
{
name: 'Name',
value: repoName + ' Repo Token' || 'Protocol.Land Repo Token',
},
{ name: 'Process-Type', value: 'token' },
{ name: 'aos-Version', value: aosDetails.version },
{
name: 'Authority',
value: 'fcoN_xJeisVsPXA-trzVAuIiqO3ydLQxM-L4XbrQKzY',
},
] as Tag[];

const pid = await spawn({
module: aosDetails.module,
tags,
scheduler: aosDetails.scheduler,
data: '1984',
signer: createDataItemSigner(getWallet()),
});

await pollForTxBeingAvailable({ txId: pid });

return pid;
}

async function getAosDetails() {
const defaultDetails = {
version: '1.10.22',
module: 'SBNb1qPQ1TDwpD_mboxm2YllmMLXpWw4U8P9Ff8W9vk',
scheduler: '_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA',
};

try {
const response = await fetch(
'https://raw.githubusercontent.com/permaweb/aos/main/package.json'
);
const pkg = (await response.json()) as {
version: string;
aos: { module: string };
};
const details = {
version: pkg?.version || defaultDetails.version,
module: pkg?.aos?.module || defaultDetails.module,
scheduler: defaultDetails.scheduler,
};
return details;
} catch {
return defaultDetails;
}
}
56 changes: 55 additions & 1 deletion src/lib/arweaveHelper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getWallet, initArweave } from './common';
import { getWallet, initArweave, waitFor } from './common';
import { Tag } from 'arweave/node/lib/transaction';
import { ArweaveSigner, createData } from 'arbundles';

Expand Down Expand Up @@ -80,3 +80,57 @@ export async function turboUpload(zipBuffer: Buffer, tags: Tag[]) {

return dataItem.id;
}

export async function pollForTxBeingAvailable({ txId }: { txId: string }): Promise<void> {
const pollingOptions = {
maxAttempts: 10,
pollingIntervalMs: 3_000,
initialBackoffMs: 7_000
}
const { maxAttempts, pollingIntervalMs, initialBackoffMs } = pollingOptions

console.log('Polling for transaction...', { txId })
await waitFor(initialBackoffMs)

let attempts = 0
while (attempts < maxAttempts) {
let transaction
attempts++

try {
const response = await initArweave().api.post('/graphql', {
query: `
query {
transaction(id: "${txId}") {
recipient
owner {
address
}
quantity {
winston
}
}
}
`
})

transaction = response?.data?.data?.transaction
} catch (err) {
// Continue retries when request errors
console.log('Failed to poll for transaction...', { err })
}

if (transaction) {
return
}
console.log('Transaction not found...', {
txId,
attempts,
maxAttempts,
pollingIntervalMs
})
await waitFor(pollingIntervalMs)
}

throw new Error('Transaction not found after polling, transaction id: ' + txId)
}