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

Feat/show invokehostfunction info #212

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
be7507f
Setup files for CodeBuild (mainnet) (#204)
jjuannn Apr 15, 2024
1221c03
Bump @babel/traverse and @trivago/prettier-plugin-sort-imports
dependabot[bot] May 9, 2024
522d73d
Merge pull request #206 from bigger-tech/dependabot/npm_and_yarn/mult…
GonzaloAlt May 9, 2024
9778107
Bump vite from 2.9.13 to 2.9.18
dependabot[bot] May 9, 2024
4ff89af
Add SorobanRPC url to constant.ts
CERP27 May 10, 2024
da220a3
Install stellar updated dependencies and buffer
CERP27 May 10, 2024
ae22185
Remove invokehostfunction case from DynamicOperationComponentFactory:
CERP27 May 10, 2024
7fbc7ed
Create GetContractFunctionInfo file with methods to get the contract …
CERP27 May 10, 2024
998b256
Create InvokeHostFunctionComponentFactory:
CERP27 May 10, 2024
bcb524f
Add Parameters and Parametros to translation:
CERP27 May 10, 2024
e4d963a
Create getMethodValue to extract the methods value from the operation…
CERP27 May 10, 2024
4c2a213
Create index.ts in soroban/utils to store the sorobanServer
CERP27 May 10, 2024
297a6be
Create ContractFunctionInfo and InputInfo interfaces
CERP27 May 10, 2024
c52b33e
Create getStellarAssetContractFunctions:
CERP27 May 10, 2024
e728cee
Update InvokeHostFunctionComponent:
CERP27 May 10, 2024
08bd6cf
Update Transaction.svelte:
CERP27 May 10, 2024
e2650f1
Remove unused CustomScVal from getMethodValue.ts
CERP27 May 13, 2024
92f2e3a
Change how getMethodsValue returns:
CERP27 May 13, 2024
9c23eb1
Merge pull request #210 from bigger-tech/dependabot/npm_and_yarn/vite…
GonzaloAlt May 13, 2024
8c319c2
Add Contract_ID to translations dictionary
CERP27 May 14, 2024
43cdab0
Update InvokeHostFunctionComponent:
CERP27 May 14, 2024
ce7ca64
Update getMethodValue:
CERP27 May 14, 2024
acf4eac
Send contractId to invokeHostFunctionComponent to show it
CERP27 May 14, 2024
3463e67
Add white-space prop to css style in Operation.ts
CERP27 May 14, 2024
3495620
Merge branch 'main' of github.com:bigger-tech/simple-stellar-signer i…
CERP27 May 15, 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
200 changes: 130 additions & 70 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,11 @@
"dependencies": {
"@creit-tech/xbull-wallet-connect": "github:Creit-Tech/xBull-Wallet-Connect",
"@stellar/freighter-api": "^1.4.0",
"@stellar/stellar-sdk": "^12.0.0-rc.2",
"@walletconnect/modal": "^2.6.1",
"@walletconnect/sign-client": "^2.9.2",
"@walletconnect/types": "^2.9.2",
"buffer": "^6.0.3",
"decode-uri-component": "^0.2.2",
"json5": "^2.2.2",
"stellar-sdk": "^11.1.0",
Expand Down
10 changes: 9 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ const {
VITE_HORIZON_NETWORK_PASSPHRASE: HORIZON_NETWORK_PASSPHRASE,
VITE_STELLAR_NETWORK: STELLAR_NETWORK,
VITE_HORIZON_URL: HORIZON_URL,
VITE_SOROBANRPC_URL: SOROBANRPC_URL,
} = import.meta.env;

export { PROJECT_ID_FOR_WALLET_CONNECT, DAPP_BASE_URL, HORIZON_NETWORK_PASSPHRASE, STELLAR_NETWORK, HORIZON_URL };
export {
PROJECT_ID_FOR_WALLET_CONNECT,
DAPP_BASE_URL,
HORIZON_NETWORK_PASSPHRASE,
STELLAR_NETWORK,
HORIZON_URL,
SOROBANRPC_URL,
};
86 changes: 57 additions & 29 deletions src/lib/components/transaction/Transaction.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { FeeBumpTransaction, Transaction, TransactionBuilder, xdr } from 'stellar-sdk';
import { createEventDispatcher } from 'svelte';
import { onMount } from 'svelte';
import { Link } from 'svelte-navigator';

import type { WalletConnectService } from '../../../lib/service/walletConnect';
Expand All @@ -15,7 +16,8 @@
import Signatures from './Signatures.svelte';
import InsufficientOperationsError from './errors/InsufficientOperationsError';
import InvalidGroupsSortError from './errors/InvalidGroupsSortError';
import DynamicOperationComponentFactory from './operations/DynamicOperationComponentFactory';
import { DynamicOperationComponentFactory } from './operations/DynamicOperationComponentFactory';
import { InvokeHostFunctionComponentFactory } from './operations/InvokeHostFunctionOperationComponentFactory';
import Operation from './operations/Operation.svelte';
import type { OperationComponent } from './operations/OperationComponent';
import OperationsGroup from './operations/OperationsGroup.svelte';
Expand Down Expand Up @@ -79,38 +81,64 @@
$areOperationsExpanded = true;
}

try {
isValidXdr = xdr.TransactionEnvelope.validateXDR(transactionMessage.xdr, 'base64');
const buildedTx = TransactionBuilder.fromXDR(transactionMessage.xdr, CURRENT_NETWORK_PASSPHRASE);

if (buildedTx instanceof FeeBumpTransaction) {
feeBumpTx = buildedTx;
tx = buildedTx.innerTransaction;
} else {
tx = buildedTx;
async function initializeTransactionData() {
try {
isValidXdr = xdr.TransactionEnvelope.validateXDR(transactionMessage.xdr, 'base64');
const buildedTx = TransactionBuilder.fromXDR(transactionMessage.xdr, CURRENT_NETWORK_PASSPHRASE);

if (buildedTx instanceof FeeBumpTransaction) {
feeBumpTx = buildedTx;
tx = buildedTx.innerTransaction;
} else {
tx = buildedTx;
}

network = CURRENT_STELLAR_NETWORK;

shortedSourceAccount = getShortedStellarKey(tx.source);

const invokeOperationIndex = tx.operations.findIndex(
(operation) => operation.type === 'invokeHostFunction',
);

if (invokeOperationIndex >= 0 && tx.operations[invokeOperationIndex]) {
const invokeHostFunctionComponentFactory = new InvokeHostFunctionComponentFactory();
const invokeOperationComponent = await invokeHostFunctionComponentFactory.create(
tx,
tx.operations[invokeOperationIndex]!,
);

transactionGroups = [invokeOperationComponent];
} else {
const dynamicOperationComponentFactory = new DynamicOperationComponentFactory();

operationComponents = tx.operations.map((operation) =>
dynamicOperationComponentFactory.create(tx, operation),
);

if (transactionMessage.operationGroups && transactionMessage.operationGroups.length > 0) {
transactionGroups = groupOperationComponents(
operationComponents,
transactionMessage.operationGroups,
);
} else {
console.info("A transaction group object wasn't provided");
transactionGroups = operationComponents;
}
}
} catch (e) {
console.error(e);
if (e instanceof InvalidGroupsSortError || InsufficientOperationsError) {
transactionGroups = operationComponents;
}
}

network = CURRENT_STELLAR_NETWORK;

shortedSourceAccount = getShortedStellarKey(tx.source);
const dynamicOperationComponentFactory = new DynamicOperationComponentFactory();

operationComponents = tx.operations.map((operation) => dynamicOperationComponentFactory.create(tx, operation));

if (transactionMessage.operationGroups && transactionMessage.operationGroups.length > 0) {
transactionGroups = groupOperationComponents(operationComponents, transactionMessage.operationGroups);
} else {
console.info("A transaction group object wasn't provided");
transactionGroups = operationComponents;
}
} catch (e) {
console.error(e);
if (e instanceof InvalidGroupsSortError || InsufficientOperationsError) {
transactionGroups = operationComponents;
}
$operationsVisibility = transactionGroups.map(() => false);
}

$operationsVisibility = transactionGroups.map(() => false);
onMount(async () => {
await initializeTransactionData();
});
</script>

{#if isValidXdr}
Expand Down
86 changes: 86 additions & 0 deletions src/lib/components/transaction/getMethodValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { xdr } from '@stellar/stellar-sdk';

import { getAccountAddress, getContractAddress } from '../../soroban/GetContractFunctionInfo';

export const getMethodValue = (arg: xdr.ScVal, type?: string): xdr.ScVal | string => {
type = (type && type.toLowerCase()) || '';
switch (type) {
case 'address':
case 'scvAddress'.toLowerCase():
if (arg.address().switch().name === 'scAddressTypeAccount')
return getAccountAddress(arg.address().accountId().ed25519().toString('hex'));
return getContractAddress(arg.address().contractId().toString('hex'));
case 'scvContractInstance'.toLowerCase():
return getContractAddress(arg.address().contractId().toString('hex'));
case 'bytes':
case 'scvBytes'.toLowerCase():
case 'scvBytesN'.toLowerCase():
return arg.bytes().toString('base64');
case 'symbol':
case 'scvSymbol'.toLowerCase():
return xdr.ScVal.scvSymbol(arg.sym().toString()).value()!.toString();
case 'scvBool'.toLowerCase():
return xdr.ScVal.scvBool(arg != null);
case 'i32'.toLowerCase():
case 'scvI32'.toLowerCase():
return arg.i32().toString();
case 'i64'.toLowerCase():
case 'scvI64'.toLowerCase():
return arg.i64().low.toString();
case 'i128'.toLowerCase():
case 'scvI128'.toLowerCase():
return arg.i128().lo().toString();
case 'i256'.toLowerCase():
case 'scvI256'.toLowerCase():
return arg.i256().loLo().toString();
case 'u64'.toLowerCase():
case 'scvU64'.toLowerCase():
return arg.u64().toString();
case 'u32'.toLowerCase():
case 'scvU32'.toLowerCase():
return arg.u32().toString();
case 'u128'.toLowerCase():
case 'scvU128'.toLowerCase():
return arg.u128().lo().toString();
case 'u256'.toLowerCase():
case 'scvU256'.toLowerCase():
return arg.u256().loLo().toString();
case 'timepoint'.toLowerCase():
case 'scvTimepoint'.toLowerCase():
return xdr.ScVal.scvTimepoint(new xdr.Uint64(arg.timepoint().high));
case 'duration'.toLowerCase():
case 'scvDuration'.toLowerCase():
return xdr.ScVal.scvDuration(new xdr.Uint64(arg.duration().high));
case 'boolean':
return xdr.ScVal.scvBool(arg.b());
case 'object':
return arg.bytes().toString('base64');
case 'scvString':
return xdr.ScVal.scvString(arg.str());
case 'map':
case 'scvMap'.toLowerCase():
return arg
.map()!
.map((a) => {
const values = getMethodValue(a.val(), a.val().switch().name);
const keys = getMethodValue(a.key(), a.key().switch().name);

return ` ${JSON.stringify(keys)}: ${values} `;
})
.toString();

case 'scvVec'.toLowerCase():
return `[${arg
.vec()!
.map((param, index) => {
return `${
arg.vec()![index]?.switch().name !== 'scvMap'
? ` ${getMethodValue(param, param.switch().name)} `
: ` {\n${getMethodValue(param, param.switch().name)}\n} `
}`;
})
.toString()}]`;
default:
return arg.value()!.toString();
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import CreateClaimableBalanceComponent from './createClaimableBalance/CreateClai
import CreatePassiveSellOfferComponent from './createPassiveSellOffer/CreatePassiveSellOfferComponent';
import EndSponsoringFutureReservesComponent from './endSponsoringFutureReserves/EndSponsoringFutureReservesComponent';
import ExtendFootprintComponent from './extendFootprint/ExtendFootprintComponent';
import InvokeHostFunctionComponent from './invokeHostFunction/InvokeHostFunctionComponent';
import LiquidityPoolDepositComponent from './liquidityPoolDeposit/LiquidityPoolDepositComponent';
import LiquidityPoolWithdrawComponent from './liquidityPoolWithdraw/LiquidityPoolWithdrawComponent';
import ManageBuyOfferComponent from './manageBuyOffer/ManageBuyOfferComponent';
Expand All @@ -35,7 +34,7 @@ import RevokeTrustlineSponsorshipComponent from './revokeTrustLineSponsorship/Re
import SetOptionsComponent from './setOptions/SetOptionsComponent';
import SetTrustLineFlagsComponent from './setTrustLineFlags/SetTrustLineFlagsComponent';

export default class DynamicOperationComponentFactory {
export class DynamicOperationComponentFactory {
create(tx: Transaction, operation: Operation): OperationComponent {
let operationComponent;

Expand Down Expand Up @@ -154,9 +153,6 @@ export default class DynamicOperationComponentFactory {
case 'clawbackClaimableBalance':
operationComponent = new ClawbackClaimableBalanceComponent(tx, operation);
break;
case 'invokeHostFunction':
operationComponent = new InvokeHostFunctionComponent(tx, operation);
break;
case 'restoreFootprint':
operationComponent = new RestoreFootprintComponent(tx, operation);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { Operation, Transaction } from 'stellar-sdk';

import { getContractAddress, getContractMethodsParams } from '../../../soroban/GetContractFunctionInfo';
import InvokeHostFunctionComponent from './invokeHostFunction/InvokeHostFunctionComponent';

export class InvokeHostFunctionComponentFactory {
async create(tx: Transaction, operation: Operation): Promise<InvokeHostFunctionComponent> {
const funcTitle = (operation as Operation.InvokeHostFunction).func.invokeContract().functionName().toString();
const contractID = getContractAddress(
(operation as Operation.InvokeHostFunction).func
.invokeContract()
.contractAddress()
.contractId()
.toString('hex'),
);
const funcParameters = await getContractMethodsParams(contractID, funcTitle);

const operationComponent = new InvokeHostFunctionComponent(
tx,
operation as Operation.InvokeHostFunction,
funcParameters[0]!,
funcTitle,
contractID,
);

return operationComponent;
}
}
1 change: 1 addition & 0 deletions src/lib/components/transaction/operations/Operation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
}

.break-key {
white-space: pre-wrap;
word-break: break-word;
letter-spacing: 0.14px;
line-height: 21px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
import type { Operation, Transaction } from 'stellar-sdk';
import { xdr } from 'stellar-sdk';
import { Operation, Transaction, xdr } from '@stellar/stellar-sdk';

import { InvokeHostFunction } from '../../../../../lib/stellar/InvokeHostFunction';
import type { ContractFunctionInfo } from '../../../../soroban/ContractFunctionInfo.interface';
import { getMethodValue } from '../../getMethodValue';
import AbstractOperationComponent from '../AbstractOperationComponent';
import type IOperationComponent from '../IOperationComponent';

export default class InvokeHostFunctionComponent extends AbstractOperationComponent implements IOperationComponent {
constructor(tx: Transaction, operation: Operation.InvokeHostFunction) {
const funcValue = operation.func.value();
let functionType = InvokeHostFunction.UploadWasm;
constructor(
tx: Transaction,
operation: Operation.InvokeHostFunction,
funcParameter: ContractFunctionInfo,
funcTitle: string,
contractID: string,
) {
const values = operation.func
.invokeContract()
.args()
.map((arg) => {
const methodValue = getMethodValue(arg, arg.switch().name);

if (funcValue instanceof xdr.InvokeContractArgs) functionType = InvokeHostFunction.InvokeContract;
if (funcValue instanceof xdr.CreateContractArgs) functionType = InvokeHostFunction.CreateContract;
if (methodValue instanceof xdr.ScVal) return methodValue.value();

return methodValue;
});

super({
title: 'OPERATION_INVOKE_HOST_FUNCTION',
operationItems: [
{ title: 'SOURCE_ACCOUNT', value: operation.source || tx.source, translatedValue: 'YOUR_ACCOUNT' },
{ title: 'FUNCTION_TYPE', value: functionType },
{ title: 'CONTRACT_ID', value: contractID },
{ title: 'FUNCTION_TYPE', value: funcTitle },
(funcParameter.description ? true : undefined) && {
title: 'DESCRIPTION',
value: [funcParameter.description!],
},
(funcParameter.inputs.length >= 1 ? true : undefined) && {
title: 'PARAMETERS',
value: funcParameter?.inputs.map((arg, index) => {
return `${arg.name} : ${values[index]!.toString().split(' ,')} `;
}),
},
],
});
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/i18n/ITranslation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface ITranslation {
CLOSE: string;
CONFIRM: string;
CONNECT_WITH_PRIVATE_KEY: string;
CONTRACT_ID: string;
DATA: string;
DESCRIPTION: string;
DESTINATION_ASSET: string;
Expand Down Expand Up @@ -113,6 +114,7 @@ export interface ITranslation {
OPERATIONS_LIST: string;
PATH: string;
PAY: string;
PARAMETERS: string;
PREAUTH_TX: string;
PRICE: string;
PRIVATE_KEY: string;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/i18n/languages/english.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"CLOSE": "Close",
"CONFIRM": "Confirm",
"CONNECT_WITH_PRIVATE_KEY": "Connect",
"CONTRACT_ID": "Contract ID:",
"DATA": "Data:",
"DESCRIPTION": "Description:",
"DESTINATION_ASSET": "Destination Asset:",
Expand Down Expand Up @@ -113,6 +114,7 @@
"OPERATIONS_LIST": "Operations list",
"PATH": "Path:",
"PAY": "Pay",
"PARAMETERS": "Parameters:",
"PREAUTH_TX": "preAuthTx:",
"PRICE": "Price:",
"PRIVATE_KEY": "Private Key",
Expand Down
2 changes: 2 additions & 0 deletions src/lib/i18n/languages/spanish.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"CLOSE": "Cerrar",
"CONFIRM": "Confirmar",
"CONNECT_WITH_PRIVATE_KEY": "Conectar",
"CONTRACT_ID": "ID de Contrato:",
"DATA": "Data:",
"DESCRIPTION": "Descripción:",
"DESTINATION_ASSET": "Activo que recibe la cuenta de destino:",
Expand Down Expand Up @@ -113,6 +114,7 @@
"OPERATIONS_LIST": "Lista de operaciones",
"PATH": "Ruta:",
"PAY": "Pagar",
"PARAMETERS": "Parametros:",
"PREAUTH_TX": "preAuthTx:",
"PRICE": "Precio:",
"PRIVATE_KEY": "Llave Privada",
Expand Down
Loading
Loading