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

Feature/crosschain-transactions #10

Open
wants to merge 96 commits into
base: devop/release-1-39
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
6cc4385
Add new components to select chain on sending transactions for Kadena…
andborges May 7, 2024
5fd1344
UI changes to display to and from chains
andborges May 8, 2024
90dbc5d
Changing transactions activity reduce
KevinKons May 8, 2024
f7e213a
Changing transaction scripts to handle crosschain transactions
andborges May 9, 2024
385bfde
Fix async/await issue in KDAToken class
andborges May 9, 2024
f8b06d8
Linting code, removing some commented code
andborges May 9, 2024
6234ecc
Merge pull request #2 from kadena-community/feature/chain-list-send-t…
KevinKons May 9, 2024
3810cf2
removing hardcoded address
KevinKons May 9, 2024
5783fd8
removing empty space
KevinKons May 9, 2024
8cf6e22
Merge branch 'feature/crosschain-transactions' into feature/kad-13-im…
KevinKons May 9, 2024
0426000
Address validation in crosschain transaction; Some small UI fixes
andborges May 9, 2024
211b2a6
Linting fixes
andborges May 9, 2024
f329e16
removing wrapper on activity handler
KevinKons May 10, 2024
eb99c7f
removing console.log
KevinKons May 10, 2024
f4fed2e
Removing console.log
KevinKons May 10, 2024
d312277
Merge pull request #3 from kadena-community/bug/send-same-account-dif…
KevinKons May 10, 2024
ba05eb5
Merge branch 'feature/crosschain-transactions' into feature/kad-13-im…
KevinKons May 10, 2024
51ee5a3
Removing comments
KevinKons May 10, 2024
59879b2
Merge pull request #4 from kadena-community/feature/kad-13-implement-…
andborges May 10, 2024
17ef97f
Fix crossChainId type in KadenaRawInfo interface
andborges May 13, 2024
7b4f41d
Refactorinf sendLocalTransacxtion to allow for different chains and o…
KevinKons May 14, 2024
af3c689
Refactoring activities to check for continuation tx
KevinKons May 14, 2024
3eac632
removing spv from Kadena activity
KevinKons May 14, 2024
fc9a983
adding transaction status when tx already continued
KevinKons May 14, 2024
004da65
Changing KadenaRawInfo type
KevinKons May 14, 2024
23854d6
adding link to transaction finisher
KevinKons May 14, 2024
1a772f4
refactoring spv call
KevinKons May 14, 2024
b27bce8
Merge remote-tracking branch 'origin/feature/crosschain-transactions'…
KevinKons May 14, 2024
bbe2086
fixing prettier
KevinKons May 14, 2024
bdfa987
Satisfying prettier
KevinKons May 14, 2024
0e647e2
Cross-chain second step transaction implementation
andborges May 14, 2024
be98c2f
Merge pull request #5 from kadena-community/feature/kad-13-implement-…
andborges May 14, 2024
68962ab
Merge branch 'feature/crosschain-transactions' into feature/send-seco…
andborges May 14, 2024
7aae063
Fix typo
andborges May 14, 2024
fcf7c5c
Merge pull request #6 from kadena-community/feature/send-second-leg-c…
KevinKons May 14, 2024
f3dfc17
Filter activities by ChainId in Kadena; duplicated tx on same account…
andborges May 15, 2024
64ee093
undoing continued ActivityStatus removal
KevinKons May 16, 2024
9effa84
adding needs_continuation activity status
KevinKons May 16, 2024
2761ee9
removing console.log
KevinKons May 16, 2024
02f3108
filter activities by chain id
KevinKons May 17, 2024
ad3fa4c
adding finish tx button
KevinKons May 21, 2024
6542d90
Making Finish Tx button redirect to confirm tx
KevinKons May 21, 2024
40f5dd1
adding TtransactionType to VerifyTransactionParams
KevinKons May 21, 2024
195c61a
Refactoring verify transaction
KevinKons May 21, 2024
d8812b1
creating verify-finish-crosschain-transaction
KevinKons May 21, 2024
46da72b
improvements on verify finish crosschain transaction
KevinKons May 21, 2024
f76618c
showing selectedAccountAddress and selectedAccountName on verify-fini…
KevinKons May 22, 2024
8c82dbd
showing transaction chain id
KevinKons May 22, 2024
83e53ea
adding createTxFeeObject util
KevinKons May 23, 2024
e68fc3c
adding send button to verify-finish-crosschain-transaction
KevinKons May 24, 2024
1dcdd87
sending finish transaction
KevinKons May 24, 2024
e312c96
Merge pull request #7 from kadena-community/bug/cross-chain-activitie…
KevinKons May 24, 2024
2934a62
removing console.log
KevinKons May 27, 2024
c55efd1
send finish transaction
KevinKons May 27, 2024
9b8888a
rafactoring send-process component
KevinKons May 27, 2024
09dfaca
Removing hardcoded chainid
KevinKons May 27, 2024
d1ae7d6
adding needs_continuation to activity status component
KevinKons May 28, 2024
f67d4a8
Merge pull request #8 from kadena-community/feature/kad-22-filter-act…
andborges May 28, 2024
d90cf63
Merge pull request #9 from kadena-community/feature/kad-25-make-finis…
andborges May 28, 2024
43eeaf8
adding waiting for spv activity status
KevinKons May 29, 2024
1ff72ed
Refactoring network-activity-transaction
KevinKons May 29, 2024
6603b0e
refactoring indentation
KevinKons May 29, 2024
e911972
console.log
KevinKons May 30, 2024
0b6089e
Adding support to Ledger for Kadena
andborges May 30, 2024
8ea87b3
Update dependencies for Ledger support on Kadena
andborges May 30, 2024
9bf0b9c
fixing bug on spv
KevinKons May 30, 2024
7b33d1e
Fix amount field behavior for decimal values
andborges May 30, 2024
d2130d9
refactoring network activity component for kadena
KevinKons May 31, 2024
aefea96
Adding executing_continuation state
KevinKons May 31, 2024
fea863d
fixing crossChainId missing
KevinKons Jun 1, 2024
451c318
fixing broken status on network-activity component
KevinKons Jun 1, 2024
108b64d
fixing missing crosschain id bug when finishing transaction
KevinKons Jun 3, 2024
78079d3
refactoring activities cache for kadena
KevinKons Jun 3, 2024
da55e64
removing unused code
KevinKons Jun 3, 2024
251f029
Merge remote-tracking branch 'origin/feature/crosschain-transactions'…
KevinKons Jun 3, 2024
a799b50
Merge pull request #12 from kadena-community/feature/cross-chain-ledger
KevinKons Jun 3, 2024
3b25928
Merge remote-tracking branch 'origin/feature/crosschain-transactions'…
KevinKons Jun 3, 2024
9b5ed94
fixing indentation
KevinKons Jun 3, 2024
ed21cb2
Show warning message when a cross-chain is detected in the Send UI
andborges Jun 3, 2024
594ba2d
Merge branch 'feature/crosschain-transactions' of github.com:kadena-c…
andborges Jun 3, 2024
0d9bd98
Update cross-chain transaction message in Send UI
andborges Jun 3, 2024
18fb092
Adding cross-chain icon
andborges Jun 3, 2024
712e2f6
fixing bug on send finish transaction
KevinKons Jun 4, 2024
6c006e4
Styling Send finish tx and Waiting for SPV chip
KevinKons Jun 4, 2024
f1ef7c3
Styling Send finish tx button and Waiting for SPV chip
KevinKons Jun 4, 2024
d9d35aa
Merge remote-tracking branch 'origin/feature/crosschain-transactions'…
KevinKons Jun 4, 2024
d7affa7
Adjusting activity text
KevinKons Jun 4, 2024
de51817
Merge pull request #11 from kadena-community/feature/kad-31-fix-wordi…
andborges Jun 4, 2024
9dd6f0f
Fix some linting issues
andborges Jun 4, 2024
21793f2
Changing styles on cross-chain-alert
KevinKons Jun 4, 2024
39dc07a
removing hardcoded network id for kadena
KevinKons Jun 4, 2024
a45e867
adding ui update verification when ActivityStatus is executing_contin…
KevinKons Jun 4, 2024
8bd0e71
Second cross-chain tx using ledger always uses gas station; Remove ha…
andborges Jun 4, 2024
f88967b
Merge branch 'feature/crosschain-transactions' of github.com:kadena-c…
andborges Jun 4, 2024
943642c
Refactor cross-chain transaction UI to use boolean check for crossCha…
andborges Jun 4, 2024
99a6819
fix: add ledger error details and improve ledger file
barthuijgen Jul 22, 2024
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
39 changes: 29 additions & 10 deletions packages/extension/src/libs/activity-state/wrap-activity-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ActivityStatus } from "@/types/activity";
import ActivityState from ".";
import { ActivityHandlerType } from "./types";
const CACHE_TTL = 1000 * 60 * 5; // 5 mins
import { ProviderName } from "@/types/provider";
export default (activityHandler: ActivityHandlerType): ActivityHandlerType => {
const returnFunction: ActivityHandlerType = async (network, address) => {
const activityState = new ActivityState();
Expand All @@ -12,19 +14,36 @@ export default (activityHandler: ActivityHandlerType): ActivityHandlerType => {
activityState.getAllActivities(options),
activityState.getCacheTime(options),
]);
if (cacheTime + CACHE_TTL < new Date().getTime()) {
const liveActivities = await activityHandler(network, address);
if (!activities.length) {
await activityState.addActivities(liveActivities, options);
await activityState.setCacheTime(options);
return liveActivities;
} else {
await activityState.addActivities(liveActivities, options);
const liveActivities = await activityHandler(network, address);
if (network.provider === ProviderName.kadena) {
if (cacheTime + CACHE_TTL < new Date().getTime()) {
const inProcessActivities = activities.filter(
(a) =>
a.status !== ActivityStatus.success &&
a.status !== ActivityStatus.failed
);
await activityState.deleteAllActivities(options);
await activityState.addActivities(
liveActivities.concat(inProcessActivities),
options
);
await activityState.setCacheTime(options);
return activityState.getAllActivities(options);
}
} else return activities;
} else {
return activities;
if (cacheTime + CACHE_TTL < new Date().getTime()) {
if (!activities.length) {
await activityState.addActivities(liveActivities, options);
await activityState.setCacheTime(options);
return liveActivities;
} else {
await activityState.addActivities(liveActivities, options);
await activityState.setCacheTime(options);
return activityState.getAllActivities(options);
}
} else {
return activities;
}
}
};
return returnFunction;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@
/>

<div class="verify-transaction-account__name">
<p v-if="from">From</p>
<p v-else>To</p>
<p v-if="from">
From
<span v-if="subnetwork">{{ subnetwork }}</span>
</p>
<p v-else>
To
<span v-if="subnetwork">{{ subnetwork }}</span>
</p>
<h4>{{ name ? name : address }}</h4>
<h6 v-show="!!name">
{{ $filters.replaceWithEllipsis(address, 6, 4) }}
Expand Down Expand Up @@ -60,6 +66,12 @@ defineProps({
return {};
},
},
subnetwork: {
type: String,
default: () => {
return null;
},
},
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Activity, ActivityStatus, ActivityType } from "@/types/activity";
import { BaseNetwork } from "@/types/base-network";
import { NetworkEndpoints, NetworkTtls } from "./configs";
import { toBase } from "@enkryptcom/utils";
import KadenaAPI from "@/providers/kadena/libs/api";
import { ChainId, Pact } from "@kadena/client";
import { KadenaNetwork } from "@/providers/kadena/types/kadena-network";

const getAddressActivity = async (
address: string,
Expand All @@ -26,10 +29,14 @@ export default async (
network: BaseNetwork,
address: string
): Promise<Activity[]> => {
const networkOptions = (network as KadenaNetwork).options;
const networkName = network.name as keyof typeof NetworkEndpoints;
const enpoint = NetworkEndpoints[networkName];
const ttl = NetworkTtls[networkName];
const activities = await getAddressActivity(
const api = (await network.api()) as KadenaAPI;
const chainId = await api.getChainId();

let activities = await getAddressActivity(
address,
enpoint,
ttl,
Expand All @@ -45,56 +52,124 @@ export default async (
.then((mdata) => (price = mdata || "0"));
}

const groupActivities = activities.reduce((acc: any, activity: any) => {
if (!acc[activity.requestKey]) {
acc[activity.requestKey] = activity;
}
if (activity.idx === 1) {
acc[activity.requestKey] = activity;
}
return acc;
}, {});

return Object.values(groupActivities).map((activity: any, i: number) => {
const rawAmount = toBase(
activity.amount
? parseFloat(activity.amount).toFixed(network.decimals)
: "0",
network.decimals
);
// note: intentionally not using fromAccount === some-value
// I want to match both null and "" in fromAccount/toAccount
// actual values will be a (truthy) string
let { fromAccount, toAccount } = activity;
if (!fromAccount && activity.crossChainAccount) {
fromAccount = activity.crossChainAccount;
}
if (!toAccount && activity.crossChainAccount) {
toAccount = activity.crossChainAccount;
const groupActivities = activities
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be simplified:

const groupdActivities = activities.reduce((acc: any, activity: any) => {
  if (activity.chain === chainId || activity.crossChainId === chainId) {
    if (!acc[activity.requestKey] || activity.idx !== 0) {
      acc[activity.requestKey] = activity;
    }
  }
  return acc;
}, {});

.filter(
(activity) =>
activity.chain == chainId || activity.crossChainId == chainId
)
.reduce((acc: any, activity: any) => {
if (!acc[activity.requestKey]) {
acc[activity.requestKey] = activity;
}
if (activity.idx !== 0) {
acc[activity.requestKey] = activity;
}
return acc;
}, {});

activities = Object.values(groupActivities).map(
(activity: any, i: number) => {
const rawAmount = toBase(
activity.amount
? parseFloat(activity.amount).toFixed(network.decimals)
: "0",
network.decimals
);

// note: intentionally not using fromAccount === some-value
// I want to match both null and "" in fromAccount/toAccount
// actual values will be a (truthy) string
let { fromAccount, toAccount } = activity;
if (!fromAccount && activity.crossChainAccount) {
fromAccount = activity.crossChainAccount;
}
if (!toAccount && activity.crossChainAccount) {
toAccount = activity.crossChainAccount;
}

return {
nonce: i.toString(),
from: fromAccount,
to: toAccount,
isIncoming:
(!activity.crossChainId && fromAccount !== address) ||
(activity.crossChainId && activity.crossChainId === chainId),
network: network.name,
rawInfo: activity,
chainId: activity.chain.toString(),
crossChainId: activity.crossChainId,
status:
activity.idx !== 0 ? ActivityStatus.success : ActivityStatus.failed,
timestamp: new Date(activity.blockTime).getTime(),
value: rawAmount,
transactionHash: activity.requestKey,
type: ActivityType.transaction,
token: {
decimals: network.decimals,
icon: network.icon,
name: network.currencyNameLong,
symbol:
activity.token !== "coin" ? activity.token : network.currencyName,
price: price,
},
};
}
return {
nonce: i.toString(),
from: fromAccount,
to: toAccount,
isIncoming: activity.fromAccount !== address,
network: network.name,
rawInfo: activity,
chainId: activity.chain.toString(),
crossChainId: activity.crossChainId,
status:
activity.idx === 1 ? ActivityStatus.success : ActivityStatus.failed,
timestamp: new Date(activity.blockTime).getTime(),
value: rawAmount,
transactionHash: activity.requestKey,
type: ActivityType.transaction,
token: {
decimals: network.decimals,
icon: network.icon,
name: network.currencyNameLong,
symbol:
activity.token !== "coin" ? activity.token : network.currencyName,
price: price,
},
};
});
);

await Promise.allSettled(
activities.map(async (activity: any) => {
if (
activity.status === ActivityStatus.success &&
activity.crossChainId !== null
) {
Comment on lines +120 to +124
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be preferable to .filter() by this condition first, and then .map(async () => ) so that we dont try to await a bunch of noop promises for no reason

const fetchSpvResponse = await fetch(
`${network.node}/${networkOptions.kadenaApiOptions.networkId}/chain/${activity.chainId}/pact/spv`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
requestKey: activity.transactionHash,
targetChainId: String(activity.crossChainId),
}),
}
);

const spv = await fetchSpvResponse.json();
activity.spv = spv;

const tx = Pact.builder
.continuation({
proof: spv,
data: {},
pactId: activity.transactionHash,
rollback: false,
step: 1,
})
.setMeta({
chainId: String(activity.rawInfo.crossChainId) as ChainId,
senderAccount: activity.from,
})
.createTransaction();

const transactionResult = await api.sendLocalTransaction(
tx,
{ signatureVerification: false, preflight: false },
String(activity.rawInfo.crossChainId) as ChainId
);

if (transactionResult.result.status === "success") {
activity.status = ActivityStatus.needs_continuation;

const gasLimit = transactionResult.metaData?.publicMeta?.gasLimit;
const gasPrice = transactionResult.metaData?.publicMeta?.gasPrice;
const gasFee = gasLimit && gasPrice ? gasLimit * gasPrice : 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this gasFee calculation. gasLimit should not be part of it, that's just the upper limit of what can be spend on a transaction and has nothing to do with the actual fee.


activity.necessaryGasFeeToContinuation = gasFee;
}
}
})
);
return activities;
};
51 changes: 39 additions & 12 deletions packages/extension/src/providers/kadena/libs/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class API implements ProviderAPIInterface {
async getBalanceByChainId(address: string, chainId: string): Promise<string> {
const balance = await this.getBalanceAPI(
this.displayAddress(address),
chainId
chainId.toString()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we calling .toString() on a string?

);

if (balance.result.status === "failure") {
Expand Down Expand Up @@ -97,23 +97,49 @@ class API implements ProviderAPIInterface {
.setNetworkId(this.networkId)
.createTransaction();

return this.dirtyRead(transaction);
return this.dirtyRead(transaction, chainId);
}

async sendLocalTransaction(
signedTranscation: ICommand
signedTransaction: ICommand | IUnsignedCommand,
options?: { signatureVerification: boolean; preflight: boolean },
_chainId?: string
): Promise<ICommandResult> {
const chainId = await this.getChainId();
const client = createClient(this.getApiHost(chainId));
return client.local(signedTranscation as ICommand);
const chainId = _chainId === undefined ? await this.getChainId() : _chainId;
const client = createClient(
this.getApiHost(chainId ?? (await this.getChainId()))
);
return client.local(signedTransaction, options);
}

async sendTransaction(
signedTranscation: ICommand
): Promise<ITransactionDescriptor> {
transaction: ICommand | IUnsignedCommand,
chainId?: string,
listen = false
): Promise<{
transactionDescriptor: ITransactionDescriptor;
commandResult: ICommandResult | undefined;
}> {
const clientChainId = chainId || (await this.getChainId());
const client = createClient(this.getApiHost(clientChainId));
const transactionDescriptor = await client.submit(transaction as ICommand);
const commandResult = listen
? await client.listen(transactionDescriptor)
: undefined;

return { transactionDescriptor, commandResult };
}

async pollCreateSpv(
transactionDescriptor: ITransactionDescriptor,
targetChainId: string
): Promise<string> {
const chainId = await this.getChainId();
const client = createClient(this.getApiHost(chainId));
return client.submit(signedTranscation as ICommand);
return client.pollCreateSpv(
transactionDescriptor,
targetChainId as ChainId
);
}

async listen(
Expand All @@ -125,10 +151,11 @@ class API implements ProviderAPIInterface {
}

async dirtyRead(
signedTranscation: ICommand | IUnsignedCommand
signedTranscation: ICommand | IUnsignedCommand,
chainId?: string
): Promise<ICommandResult> {
const chainId = await this.getChainId();
const client = createClient(this.getApiHost(chainId));
const clientChainId = chainId || (await this.getChainId());
const client = createClient(this.getApiHost(clientChainId));
return client.dirtyRead(signedTranscation);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const method: MiddlewareFunction = function (
return {
address: this.network.displayAddress(acc.address),
publicKey: acc.publicKey.replace("0x", ""),
isHardware: acc.isHardware,
genesisHash: "",
name: acc.name,
type: acc.signerType,
Expand Down
Loading