From 1d781d6e4ce5bda520e210c83fc9680783f32fb1 Mon Sep 17 00:00:00 2001 From: Guillaume De Martino Date: Wed, 20 Sep 2023 23:23:36 +0200 Subject: [PATCH 1/3] fix IssueCard display error --- components/IssueCard.tsx | 67 ++++++++++++++++++++++++++++------------ pages/issues/index.tsx | 13 +++++--- services/issues.ts | 6 ++-- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/components/IssueCard.tsx b/components/IssueCard.tsx index e61a4c1..33f7993 100644 --- a/components/IssueCard.tsx +++ b/components/IssueCard.tsx @@ -9,6 +9,11 @@ import { TxOutputRef } from 'scrypt-ts'; import axios from 'axios'; import { parse } from 'path'; +import artifact from "../artifacts/issue.json"; +import Link from 'next/link'; + +Issue.loadArtifact(artifact) + export interface Signer { // Define the properties of the Signer interface as per your requirement @@ -32,6 +37,7 @@ interface Comment { interface IssueCardProps { issue: Issue; + contractLocation: string; onAddBounty: (issue: Issue) => Promise; onLeaveComment: (issue: Issue) => Promise; onMarkAsComplete: (issue: Issue) => Promise; @@ -42,6 +48,7 @@ interface IssueCardProps { const IssueCard: React.FC = (props: { issue: Issue, + contractLocation: string, onAddBounty: (issue: Issue) => Promise, onLeaveComment: (issue: Issue) => Promise, onMarkAsComplete: (issue: Issue) => Promise, @@ -53,10 +60,10 @@ const IssueCard: React.FC = (props: { const [addingBounty, setAddingBounty] = useState(false); const [satoshis, setSatoshis] = useState(null); - const [newBounty, setNewBounty] = useState(BigInt(props.issue.balance -1)); + const [newBounty, setNewBounty] = useState(0n); const [issue, setIssue] = useState(props.issue); - const [location, setLocation] = useState((props.issue.from as TxOutputRef)?.tx?.hash); - const [origin, setOrigin] = useState(null); + const [location, setLocation] = useState(props.contractLocation); + const [origin, setOrigin] = useState(props.origin); const [completionStatus, setCompletionStatus] = useState<'incomplete' | 'posting' | 'complete'>('incomplete'); const [commentBoxVisible, setCommentBoxVisible] = useState(false); const [newComment, setNewComment] = useState(''); @@ -66,6 +73,21 @@ const IssueCard: React.FC = (props: { const [assignPopupVisible, setAssignPopupVisible] = useState(false); const [publicKeyInput, setPublicKeyInput] = useState(''); + useEffect(() => { + + if(location){ + + let [txid, vout] = location.split('_') + axios.get(`https://api.whatsonchain.com/v1/bsv/main/tx/hash/${txid}`).then((resp) => { + console.log("location tx", resp.data.vout[vout]) + let amount = Math.round(resp.data.vout[vout].value * 1e8) + setNewBounty(BigInt(amount) - 1n) + }) + + } + + },[location]) + const handleAssignButtonClick = () => { setAssignPopupVisible(true); }; @@ -105,7 +127,10 @@ const IssueCard: React.FC = (props: { }); console.log({ result }) setIssue(newIssue); - setNewBounty(BigInt(newIssue.balance - 1)); + let [txid,vout] = result.data.contract.location.split('_') + let newLocTx = await axios.get(`https://api.whatsonchain.com/v1/bsv/main/tx/hash/${txid}`) + let amount = Math.round(newLocTx.data.vout[vout].value * 1e8) + setNewBounty(BigInt(amount)- 1n) props.refresh(); setAssignSuccess(true); @@ -187,7 +212,10 @@ useEffect(() => { const result = await axios.get(`https://pow.co/api/v1/issues/${(newIssue.from as TxOutputRef)?.tx?.hash}`); console.log({ result }) setIssue(newIssue); - setNewBounty(BigInt(newIssue.balance - 1)); + let [txid,vout] = result.data.contract.location.split('_') + let newLocTx = await axios.get(`https://api.whatsonchain.com/v1/bsv/main/tx/hash/${txid}`) + let amount = Math.round(newLocTx.data.vout[vout].value * 1e8) + setNewBounty(BigInt(amount)- 1n) props.refresh(); }; @@ -230,7 +258,10 @@ useEffect(() => { const result = await axios.get(`https://pow.co/api/v1/issues/${tx.hash}`); console.log({ result }) setIssue(newIssue); - setNewBounty(BigInt(newIssue.balance - 1)); + let [txid,vout] = result.data.contract.location.split('_') + let newLocTx = await axios.get(`https://api.whatsonchain.com/v1/bsv/main/tx/hash/${txid}`) + let amount = Math.round(newLocTx.data.vout[vout].value * 1e8) + setNewBounty(BigInt(amount)- 1n) props.refresh(); // Assuming onLeaveComment is a function that posts the comment and returns the JSON response @@ -245,21 +276,18 @@ useEffect(() => { } }; - const title = Buffer.from(issue.title, 'hex').toString('utf8'); - const description = Buffer.from(issue.description, 'hex').toString('utf8'); - const organization = Buffer.from(issue.organization, 'hex').toString('utf8'); - const repo = Buffer.from(issue.repo, 'hex').toString('utf8'); - - console.log('ORIGIN', props.origin) return ( -
-

{title}

-

{organization}/{repo}

-

{description}

-

Bounty: {newBounty.toString()}

-

Location: {props.origin.location}

-

Origin: {props.origin.origin}

+
+ +

{issue.title}

+ +
+

{issue.organization}/{issue.repo}

+

{issue.description}

+

Bounty: {newBounty.toString()} sats

+

Location: {location}

+

Origin: {origin}

@@ -351,6 +379,7 @@ useEffect(() => { ))} +
); diff --git a/pages/issues/index.tsx b/pages/issues/index.tsx index 9cc48de..476e007 100644 --- a/pages/issues/index.tsx +++ b/pages/issues/index.tsx @@ -19,18 +19,21 @@ export interface ScryptRanking { const RankedIssueCard = ({origin, totaldifficulty}: ScryptRanking) => { const [issue, setIssue] = useState(null) + const [location, setLocation] = useState(null) const wallet = useWallet() const getIssueData = () => { - getIssue({txid: origin}).then((data) => { - console.log(data) - setIssue(data) + getIssue({txid: origin.split('_')[0]}).then((data) => { + console.log("issue data", data) + setIssue(data.props) + setLocation(data.location) }) } useEffect(() => { - getIssueData() + console.log(origin) + getIssueData() },[origin]) const handleRefresh = () => { @@ -54,7 +57,7 @@ const RankedIssueCard = ({origin, totaldifficulty}: ScryptRanking) => { } return (
- + {issue ? : "loading"}
) } diff --git a/services/issues.ts b/services/issues.ts index 4da6bf6..57fce33 100644 --- a/services/issues.ts +++ b/services/issues.ts @@ -243,13 +243,13 @@ export interface NewIssue { return issue; } - export async function getIssue({ txid }: {txid: string}): Promise { + export async function getIssue({ txid }: {txid: string}): Promise { try { const { data } = await axios.get(`https://pow.co/api/v1/issues/${txid}`) - - return data.issue as Issue + console.log(data) + return data.origin } catch(error) { From 26e5e32e2e2fb66a0e2471e73bfae7ec717aef44 Mon Sep 17 00:00:00 2001 From: Guillaume De Martino Date: Wed, 20 Sep 2023 23:56:07 +0200 Subject: [PATCH 2/3] create issue operator --- services/calendar_event_operator.ts | 3 +- services/issue_operator.ts | 131 ++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 services/issue_operator.ts diff --git a/services/calendar_event_operator.ts b/services/calendar_event_operator.ts index 63ee047..52cc59b 100644 --- a/services/calendar_event_operator.ts +++ b/services/calendar_event_operator.ts @@ -4,10 +4,9 @@ import { Meeting } from '../src/contracts/meeting'; import ContractOperator from "./contract_operator"; import { fetchTransaction } from './whatsonchain'; -import { Meeting as MeetingContract } from "../src/contracts/meeting" import artifact from "../artifacts/meeting.json"; -MeetingContract.loadArtifact(artifact); +Meeting.loadArtifact(artifact); export class CalendarEventOperator extends ContractOperator { diff --git a/services/issue_operator.ts b/services/issue_operator.ts new file mode 100644 index 0000000..22ade96 --- /dev/null +++ b/services/issue_operator.ts @@ -0,0 +1,131 @@ +import { ContractTransaction, HashedSet, MethodCallOptions, PubKey, Signer, bsv, findSig, hash160 } from 'scrypt-ts'; +import { Issue } from "../src/contracts/issue"; + +import ContractOperator from "./contract_operator"; +import { fetchTransaction } from "./whatsonchain"; + +import artifact from '../artifacts/issue.json' + +Issue.loadArtifact(artifact) + +export class IssueOperator extends ContractOperator { + + static async load({ origin, signer }: { origin: string, signer: Signer }): Promise { + + // load record from server to get current location and pre-image of hashed props + + const { location, props } = await ContractOperator.loadRecord({ origin }); + + // load current location transaction from blockchain + + //const tx = await fetchTransaction({ txid: location.split('_')[0] }); + //temporary hack + const tx = await fetchTransaction({ txid: origin}); + + // initialize all HashSet / HashedMap props + const invitees = new HashedSet() + const attendees = new HashedSet() + + // fill values based on props (pre-images) from server + if (props.invitees){ + props.invitees.forEach((str: string) => { + invitees.add(PubKey(str)) + }); + } + if (props.attendees){ + props.attendees.forEach((str: string) => { + attendees.add(PubKey(str)) + }); + } + + let contract + try { + contract = Issue.fromTx(tx, 0, { + invitees, + attendees + }); + + console.log("contract",contract) + + } catch (error) { + throw error + } + + return new IssueOperator({ origin, contract, signer }); + } + + async close(): Promise { + + return null + + } + + async complete(): Promise { + + return null + + } + + async assign(): Promise { + + return null + + } + + async addBounty(satoshis: bigint): Promise { + + this.contract.bindTxBuilder('addBounty', async ( + current: Issue, + options: MethodCallOptions + ): Promise => { + + const nextInstance = current.next() + + const newBalance = current.balance + Number(satoshis) + + const tx = new bsv.Transaction() + tx.addInput(current.buildContractInput(options.fromUTXO)).addOutput( + new bsv.Transaction.Output({ + script: nextInstance.lockingScript, + satoshis: newBalance + }) + ) + const changeAddress = await this.signer.getDefaultAddress() + tx.change(changeAddress) + + return Promise.resolve({ + tx, + atInputIndex: 0, + nexts: [ + { + instance: nextInstance, + balance: newBalance, + atOutputIndex: 0 + } + ] + }) + }) + + const { tx } = await this.contract.methods.addBounty(satoshis) + + this.contract = Issue.fromTx(tx,0) + + return this + + + + } + + async addComment(): Promise { + + return null + + } + + async reopen(): Promise { + + return null + + } + +} \ No newline at end of file From 162d89993a5fa320b6b2bfee4961241ef4a5dcf8 Mon Sep 17 00:00:00 2001 From: Guillaume De Martino Date: Thu, 21 Sep 2023 00:08:09 +0200 Subject: [PATCH 3/3] fix compile error --- pages/issues/[txid].tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/issues/[txid].tsx b/pages/issues/[txid].tsx index f6abe02..8c7e82e 100644 --- a/pages/issues/[txid].tsx +++ b/pages/issues/[txid].tsx @@ -106,6 +106,7 @@ const IssuePage = () => { onMarkAsComplete={onMarkAsComplete} refresh={refresh} origin={origin} + contractLocation={origin} methodCalls={methodCalls} />