diff --git a/docker/colony-cdapp-dev-env-auth-proxy b/docker/colony-cdapp-dev-env-auth-proxy
index 85a91593216..adbe1937ed9 100644
--- a/docker/colony-cdapp-dev-env-auth-proxy
+++ b/docker/colony-cdapp-dev-env-auth-proxy
@@ -1,6 +1,6 @@
FROM colony-cdapp-dev-env/base:latest
-ENV AUTH_PROXY_HASH=4326771fb553e8afc70f7b3860825e80cc321eae
+ENV AUTH_PROXY_HASH=1b8da32237859df08129bc90cc6907564e3b011e
# Add dependencies from the host
# Note: these are listed individually so that if they change, they won't affect
diff --git a/src/apollo/apolloClient.ts b/src/apollo/apolloClient.ts
index 17faa986808..74f4bfbf201 100644
--- a/src/apollo/apolloClient.ts
+++ b/src/apollo/apolloClient.ts
@@ -1,38 +1,61 @@
-import { ApolloClient, from } from '@apollo/client';
+import { ApolloClient, ApolloLink, HttpLink, from } from '@apollo/client';
import { createAuthLink, AUTH_TYPE } from 'aws-appsync-auth-link';
import { createSubscriptionHandshakeLink } from 'aws-appsync-subscription-link';
import cache from './cache/index.ts';
import removeTypenameLink from './removeTypenameLink.ts';
-const auth = {
- type: AUTH_TYPE.API_KEY as const,
- apiKey: 'da2-fakeApiId123456',
-};
-
-// const noAuth = {
-// type: AUTH_TYPE.NONE as const,
+// const auth = {
+// type: AUTH_TYPE.API_KEY as const,
+// apiKey: 'da2-fakeApiId123456',
// };
-const authLink = createAuthLink({
- // url: `${
- // import.meta.env.AUTH_PROXY_ENDPOINT || 'http://localhost:3005'
- // }/graphql`,
- url: 'http://localhost:20002/graphql',
+const noAuth = {
+ type: AUTH_TYPE.NONE as const,
+};
+
+const httpLink = createAuthLink({
+ url: `${
+ import.meta.env.AUTH_PROXY_ENDPOINT || 'http://localhost:3005'
+ }/graphql`,
region: 'us-east-1',
- auth,
+ // auth is handled by auth proxy
+ auth: noAuth,
+ // auth,
});
const subscriptionLink = createSubscriptionHandshakeLink({
- url: 'http://localhost:20002/graphql',
+ url: `${
+ import.meta.env.AUTH_PROXY_ENDPOINT || 'http://localhost:3005'
+ }/graphql`,
region: 'us-east-1',
- auth,
+ // auth is handled by auth proxy
+ auth: noAuth,
+ // auth,
+});
+
+// Middleware link for setting credentials to include (aws links do not do that!)
+const authLink = new ApolloLink((operation, forward) => {
+ operation.setContext({
+ // ensures cookies are sent with every request
+ credentials: 'include',
+ });
+
+ return forward(operation);
});
+// const httpLink = new HttpLink({
+// uri: `${
+// import.meta.env.AUTH_PROXY_ENDPOINT || 'http://localhost:3005'
+// }/graphql`,
+// credentials: 'include',
+// });
+
const apolloClient = new ApolloClient({
- link: from([removeTypenameLink, authLink, subscriptionLink]),
- connectToDevTools: true,
cache,
+ connectToDevTools: true,
+ link: from([removeTypenameLink, authLink, httpLink, subscriptionLink]),
+ // link: from([removeTypenameLink, httpLink]),
/*
* @TODO Most likely we'll need to add resolvers here as well
*/
diff --git a/src/components/common/Extensions/UserNavigation/hooks.ts b/src/components/common/Extensions/UserNavigation/hooks.ts
index 7d9466bc448..0552309ef17 100644
--- a/src/components/common/Extensions/UserNavigation/hooks.ts
+++ b/src/components/common/Extensions/UserNavigation/hooks.ts
@@ -19,6 +19,8 @@ import { groupBy, unionBy } from '~utils/lodash.ts';
export const TRANSACTION_LIST_PAGE_SIZE = 10;
+// FIXME: delete all of this, this is weird
+
const sortAndGroupTransactions = (transactions: Transaction[]) => {
// Create groups of transations which have 'em
const groupedTransactions = groupBy(transactions, 'groupId');
@@ -119,6 +121,7 @@ const updateQuery = (prev, { fetchMoreResult }) => {
};
};
+// FIXME: delete this (check all places where its being used)
export const useGroupedTransactionsAndMessages = (): {
transactionAndMessageGroups: TransactionOrMessageGroups;
fetchMoreTransactions: () => void;
diff --git a/src/components/v5/frame/ColonyHome/ColonyHome.tsx b/src/components/v5/frame/ColonyHome/ColonyHome.tsx
index 242682b713a..f64cfe9ce00 100644
--- a/src/components/v5/frame/ColonyHome/ColonyHome.tsx
+++ b/src/components/v5/frame/ColonyHome/ColonyHome.tsx
@@ -17,6 +17,8 @@ import { setQueryParamOnUrl } from '~utils/urls.ts';
// import TmpAdvancedPayments from '~v5/payments/TmpAdvancedPayments.tsx';
import Link from '~v5/shared/Link/index.ts';
+import { useGroupedTransactions } from '../../../../state/useUserTransactions.ts';
+
import Agreements from './partials/Agreements/index.ts';
import DashboardHeader from './partials/DashboardHeader/index.ts';
import LeaveColonyModal from './partials/LeaveColonyModal/index.ts';
@@ -34,6 +36,8 @@ const ColonyHome = () => {
const teamsBreadcrumbs = useCreateTeamBreadcrumbs();
useSetPageBreadcrumbs(teamsBreadcrumbs);
+ const tx = useGroupedTransactions();
+ console.log('tx', tx);
return (
diff --git a/src/redux/sagas/utils/createActionMetadata.ts b/src/redux/sagas/utils/createActionMetadata.ts
index 15105da403f..9472fe5074a 100644
--- a/src/redux/sagas/utils/createActionMetadata.ts
+++ b/src/redux/sagas/utils/createActionMetadata.ts
@@ -21,3 +21,23 @@ export function* createActionMetadataInDB(txHash: string, customTitle: string) {
},
});
}
+
+export const createActionMetadataInDb__NEW = async (
+ txHash: string,
+ customTitle: string,
+) => {
+ const apolloClient = getContext(ContextModule.ApolloClient);
+
+ return apolloClient.mutate<
+ CreateColonyActionMetadataMutation,
+ CreateColonyActionMetadataMutationVariables
+ >({
+ mutation: CreateColonyActionMetadataDocument,
+ variables: {
+ input: {
+ id: txHash,
+ customTitle,
+ },
+ },
+ });
+};
diff --git a/src/redux/sagas/utils/getCanUserSendMetatransactions.ts b/src/redux/sagas/utils/getCanUserSendMetatransactions.ts
index 755160ffe89..ac469ee67c8 100644
--- a/src/redux/sagas/utils/getCanUserSendMetatransactions.ts
+++ b/src/redux/sagas/utils/getCanUserSendMetatransactions.ts
@@ -31,8 +31,7 @@ export function* getCanUserSendMetatransactions() {
});
const userHasMetatransactionEnabled =
- data.getUserByAddress?.items[0]?.profile?.meta?.metatransactionsEnabled ||
- false;
+ !!data.getUserByAddress?.items[0]?.profile?.meta?.metatransactionsEnabled;
return userHasMetatransactionEnabled;
}
diff --git a/src/state/ColonyManager.ts b/src/state/ColonyManager.ts
new file mode 100644
index 00000000000..2b640185789
--- /dev/null
+++ b/src/state/ColonyManager.ts
@@ -0,0 +1,75 @@
+import { ColonyNetwork, type Colony, PinataAdapter } from '@colony/sdk';
+
+import { ContextModule, getContext } from '~context/index.ts';
+import { Network } from '~types/network.ts';
+import { isFullWallet } from '~types/wallet.ts';
+
+// FIXME: remove
+const PINATA_JWT__TEMP = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiJlZWNiZWNhMi0wMmU3LTQ4OTYtYWMzMi03MDQyMjc3OGEyYjciLCJlbWFpbCI6ImNocmlzQGNvbG9ueS5pbyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwaW5fcG9saWN5Ijp7InJlZ2lvbnMiOlt7ImlkIjoiRlJBMSIsImRlc2lyZWRSZXBsaWNhdGlvbkNvdW50IjoxfV0sInZlcnNpb24iOjF9LCJtZmFfZW5hYmxlZCI6ZmFsc2UsInN0YXR1cyI6IkFDVElWRSJ9LCJhdXRoZW50aWNhdGlvblR5cGUiOiJzY29wZWRLZXkiLCJzY29wZWRLZXlLZXkiOiIxYTFjZmNlOTI3MzYzODI1Mjg5OSIsInNjb3BlZEtleVNlY3JldCI6IjhjZTExNTNlNTY1NjJlZDUyODJmZGU3MWYzNmYyNjhmYjU5MjAxZGI5ZmY0OWNlMTZkNTRjZGIyMDJjMWIwNGQiLCJpYXQiOjE3MTE0Nzc4Mzh9.I-aALCEpRZksUxJFaHOlk9kW03mnyyh74hXaskIfA-U`;
+
+class ColonyManager {
+ colonies: Map
;
+
+ colonyNetwork?: ColonyNetwork;
+
+ constructor() {
+ this.colonies = new Map();
+ }
+
+ async getColonyNetwork() {
+ if (this.colonyNetwork) {
+ return this.colonyNetwork;
+ }
+
+ const wallet = getContext(ContextModule.Wallet);
+
+ if (!isFullWallet(wallet)) {
+ throw new Error('Background login not yet completed.');
+ }
+
+ const signer = wallet.ethersProvider.getSigner();
+
+ const reputationOracleUrl = import.meta.env.REPUTATION_ORACLE_ENDPOINT
+ ? new URL(import.meta.env.REPUTATION_ORACLE_ENDPOINT)
+ : new URL(`/reputation`, window.location.origin);
+
+ if (import.meta.env.DEV && import.meta.env.NETWORK_ID === Network.Ganache) {
+ const ganacheAccountsUrl = new URL(
+ import.meta.env.VITE_NETWORK_FILES_ENDPOINT || 'http://localhost:3006',
+ );
+ const fetchRes = await fetch(
+ `${ganacheAccountsUrl.href}etherrouter-address.json`,
+ );
+ const { etherRouterAddress: customNetworkAddress } =
+ await fetchRes.json();
+
+ this.colonyNetwork = new ColonyNetwork(signer, {
+ customNetworkAddress,
+ reputationOracleEndpoint: reputationOracleUrl.href,
+ ipfsAdapter: new PinataAdapter(PINATA_JWT__TEMP),
+ });
+
+ return this.colonyNetwork;
+ }
+
+ this.colonyNetwork = new ColonyNetwork(signer, {
+ reputationOracleEndpoint: reputationOracleUrl.href,
+ ipfsAdapter: new PinataAdapter(PINATA_JWT__TEMP),
+ });
+
+ return this.colonyNetwork;
+ }
+
+ async getColony(colonyAddress: string) {
+ if (this.colonies.has(colonyAddress)) {
+ return this.colonies.get(colonyAddress);
+ }
+
+ const colonyNetwork = await this.getColonyNetwork();
+ const colony = await colonyNetwork.getColony(colonyAddress);
+ this.colonies.set(colonyAddress, colony);
+ return colony;
+ }
+}
+
+export default ColonyManager;
diff --git a/src/state/transactions.ts b/src/state/transactions.ts
new file mode 100644
index 00000000000..26bfa2585f9
--- /dev/null
+++ b/src/state/transactions.ts
@@ -0,0 +1,37 @@
+import { create } from 'zustand';
+import { devtools } from 'zustand/middleware';
+import { immer } from 'zustand/middleware/immer';
+
+import ColonyManager from './ColonyManager.ts';
+
+export const colonyManager = new ColonyManager();
+
+export enum TxStatus {
+ Created = 'CREATED',
+ Ready = 'READY',
+ Sent = 'SENT',
+ Mined = 'MINED',
+ Error = 'ERROR',
+}
+
+interface Transaction {
+ id: string;
+ name: string;
+ group?: {
+ key: string;
+ index: number;
+ };
+ status: TxStatus;
+}
+
+export interface TransactionsState {
+ transactions: Array;
+}
+
+export const useTransactionsStore = create()(
+ devtools(
+ immer(() => ({
+ transactions: [],
+ })),
+ ),
+);
diff --git a/src/state/transactions/moveFunds.ts b/src/state/transactions/moveFunds.ts
new file mode 100644
index 00000000000..effad9d69b2
--- /dev/null
+++ b/src/state/transactions/moveFunds.ts
@@ -0,0 +1,284 @@
+import { randomUUID } from 'crypto';
+import { type BigNumber } from 'ethers';
+
+import { createActionMetadataInDb__NEW } from '~redux/sagas/utils/createActionMetadata.ts';
+import { type Domain } from '~types/graphql.ts';
+import { type Address } from '~types/index.ts';
+
+import {
+ colonyManager,
+ useTransactionsStore,
+ TxStatus,
+} from '../transactions.ts';
+
+export const moveFunds = async (
+ {
+ colonyAddress,
+ colonyName,
+ fromDomain,
+ toDomain,
+ amount,
+ tokenAddress,
+ annotationMessage,
+ customActionTitle,
+ }: {
+ colonyAddress: Address;
+ customActionTitle: string;
+ colonyName?: string;
+ tokenAddress: Address;
+ fromDomain: Domain;
+ toDomain: Domain;
+ amount: BigNumber;
+ annotationMessage?: string;
+ },
+ { setTxHash, navigate },
+) => {
+ /*
+ * Validate the required values for the payment
+ */
+ if (!fromDomain) {
+ throw new Error(
+ 'Source domain not set for moveFundsBetweenPots transaction',
+ );
+ }
+ if (!toDomain) {
+ throw new Error(
+ 'Recipient domain not set for moveFundsBetweenPots transaction',
+ );
+ }
+ if (!amount) {
+ throw new Error(
+ 'Payment amount not set for moveFundsBetweenPots transaction',
+ );
+ }
+ if (!tokenAddress) {
+ throw new Error(
+ 'Payment token not set for moveFundsBetweenPots transaction',
+ );
+ }
+
+ const { nativeId: fromTeam } = fromDomain;
+ const { nativeId: toTeam } = toDomain;
+
+ // setup batch id
+ const batchKey = 'moveFunds';
+
+ const moveFundsId = randomUUID();
+ const annotateMoveFundsId = randomUUID();
+
+ useTransactionsStore.setState((state) => {
+ state.transactions.push({
+ id: moveFundsId,
+ // We could use an enum here ORR maybe do something smart with colony SDK
+ name: 'moveFundsBetweenPots',
+ group: {
+ key: batchKey,
+ index: 0,
+ },
+ status: TxStatus.Ready,
+ });
+ state.transactions.push({
+ id: annotateMoveFundsId,
+ // We could use an enum here ORR maybe do something smart with colony SDK
+ name: 'annotateTransaction',
+ group: {
+ key: batchKey,
+ index: 1,
+ },
+ status: TxStatus.Created,
+ });
+ });
+
+ const colony = await colonyManager.getColony(colonyAddress);
+
+ if (!colony) {
+ throw new Error(`Colony with address ${colonyAddress} not found`);
+ }
+
+ const [{ hash }, waitForMoveFunds] = await colony
+ .moveFundsToTeam(amount, toTeam, fromTeam, tokenAddress)
+ .tx()
+ .send();
+
+ useTransactionsStore.setState((state) => {
+ const tx = state.transactions.find(({ id }) => id === moveFundsId);
+ if (tx) {
+ tx.status = TxStatus.Ready;
+ }
+ });
+
+ await createActionMetadataInDb__NEW(hash, customActionTitle);
+
+ if (annotationMessage) {
+ await colony
+ .annotateTransaction(hash, { annotationMsg: annotationMessage })
+ .tx()
+ .mined();
+ }
+
+ // This is probably mined by now, just for good measure we'll wait for it
+ await waitForMoveFunds();
+
+ useTransactionsStore.setState((state) => {
+ const moveFundsTx = state.transactions.find(({ id }) => id === moveFundsId);
+ if (moveFundsTx) {
+ moveFundsTx.status = TxStatus.Mined;
+ }
+ const annotateTx = state.transactions.find(
+ ({ id }) => id === annotateMoveFundsId,
+ );
+ if (annotateTx) {
+ annotateTx.status = TxStatus.Mined;
+ }
+ });
+
+ setTxHash?.(hash);
+
+ if (colonyName && navigate) {
+ navigate(`/${colonyName}?tx=${hash}`, {
+ state: { isRedirect: true },
+ });
+ }
+};
+
+// function* createMoveFundsAction({
+// payload: {
+// colonyAddress,
+// colonyName,
+// fromDomain,
+// toDomain,
+// amount,
+// tokenAddress,
+// annotationMessage,
+// customActionTitle,
+// },
+// meta: { id: metaId, navigate, setTxHash },
+// meta,
+// }: Action) {
+// let txChannel;
+// try {
+// /*
+// * Validate the required values for the payment
+// */
+// if (!fromDomain) {
+// throw new Error(
+// 'Source domain not set for moveFundsBetweenPots transaction',
+// );
+// }
+// if (!toDomain) {
+// throw new Error(
+// 'Recipient domain not set for moveFundsBetweenPots transaction',
+// );
+// }
+// if (!amount) {
+// throw new Error(
+// 'Payment amount not set for moveFundsBetweenPots transaction',
+// );
+// }
+// if (!tokenAddress) {
+// throw new Error(
+// 'Payment token not set for moveFundsBetweenPots transaction',
+// );
+// }
+//
+// const { nativeFundingPotId: fromPot } = fromDomain;
+// const { nativeFundingPotId: toPot } = toDomain;
+//
+// // setup batch id
+// const batchKey = 'moveFunds';
+//
+// yield fork(createTransaction, moveFunds.id, {
+// context: ClientType.ColonyClient,
+// methodName:
+// 'moveFundsBetweenPots(uint256,uint256,uint256,uint256,uint256,uint256,address)',
+// identifier: colonyAddress,
+// params: [],
+// group: {
+// key: batchKey,
+// id: metaId,
+// index: 0,
+// },
+// ready: false,
+// });
+//
+// if (annotationMessage) {
+// yield fork(createTransaction, annotateMoveFunds.id, {
+// context: ClientType.ColonyClient,
+// methodName: 'annotateTransaction',
+// identifier: colonyAddress,
+// params: [],
+// group: {
+// key: batchKey,
+// id: metaId,
+// index: 1,
+// },
+// ready: false,
+// });
+// }
+//
+// yield takeFrom(moveFunds.channel, ActionTypes.TRANSACTION_CREATED);
+//
+// if (annotationMessage) {
+// yield takeFrom(
+// annotateMoveFunds.channel,
+// ActionTypes.TRANSACTION_CREATED,
+// );
+// }
+//
+// yield put(transactionPending(moveFunds.id));
+//
+// const [permissionDomainId, fromChildSkillIndex, toChildSkillIndex] =
+// yield getMoveFundsPermissionProofs(colonyAddress, fromPot, toPot);
+//
+// yield put(
+// transactionAddParams(moveFunds.id, [
+// permissionDomainId,
+// fromChildSkillIndex,
+// toChildSkillIndex,
+// fromPot,
+// toPot,
+// amount,
+// tokenAddress,
+// ]),
+// );
+//
+// yield initiateTransaction({ id: moveFunds.id });
+//
+// const {
+// payload: {
+// receipt: { transactionHash: txHash },
+// },
+// } = yield waitForTxResult(moveFunds.channel);
+//
+// yield createActionMetadataInDB(txHash, customActionTitle);
+//
+// if (annotationMessage) {
+// yield uploadAnnotation({
+// txChannel: annotateMoveFunds,
+// message: annotationMessage,
+// txHash,
+// });
+// }
+//
+// setTxHash?.(txHash);
+//
+// yield put({
+// type: ActionTypes.ACTION_MOVE_FUNDS_SUCCESS,
+// meta,
+// });
+//
+// if (colonyName && navigate) {
+// navigate(`/${colonyName}?tx=${txHash}`, {
+// state: { isRedirect: true },
+// });
+// }
+// } catch (caughtError) {
+// yield putError(ActionTypes.ACTION_MOVE_FUNDS_ERROR, caughtError, meta);
+// } finally {
+// txChannel.close();
+// }
+// }
+//
+// export default function* moveFundsActionSaga() {
+// yield takeEvery(ActionTypes.ACTION_MOVE_FUNDS, createMoveFundsAction);
+// }
diff --git a/src/state/useUserTransactions.ts b/src/state/useUserTransactions.ts
index 7fa759a4f97..2dfc3895737 100644
--- a/src/state/useUserTransactions.ts
+++ b/src/state/useUserTransactions.ts
@@ -20,6 +20,8 @@ export const useGroupedTransactions = () => {
onData: ({ client, data }) => {
const newTx = data?.data?.onCreateTransactionFrom;
+ console.log('new tx data', newTx);
+
if (!newTx) {
return;
}
@@ -56,6 +58,8 @@ export const useGroupedTransactions = () => {
skip: !user,
});
+ console.log(data);
+
const groupedAndSorted = useMemo(() => {
const rawTransactions = data?.getTransactionsByUser?.items || [];
return filter(