Skip to content

Commit 15dbf22

Browse files
authored
Bugfix/rm auth param names (#2244)
* ensure invoke host function tx shows contract parameters * add test for fallback if contract spec retrieval fails * do not show contract parameters for authorizations * add tests for create contract v1 and invoke contract * add issuer for changeTrust op (#2246) * add issuer for changeTrust op * programmatically disable overflow:hidden when copying a value * Revert "add issuer for changeTrust op (#2246)" (#2247) This reverts commit 19c8a68.
1 parent c5b1ff2 commit 15dbf22

File tree

3 files changed

+234
-4
lines changed

3 files changed

+234
-4
lines changed

extension/src/popup/components/AuthEntry/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const AuthEntries = ({ invocations }: AuthEntriesProps) => {
8181
args={detail.args}
8282
contractId={detail.contractId}
8383
fnName={detail.fnName}
84+
isAuthEntry
8485
/>
8586
</div>
8687
</div>
@@ -148,13 +149,18 @@ export const AuthEntries = ({ invocations }: AuthEntriesProps) => {
148149
{details.map((detail, ind) => (
149150
<div
150151
className="AuthEntryContainer"
152+
data-testid="AuthEntryContainer"
151153
key={`${invocation.toXDR("raw").toString()}-${ind}`}
152154
>
153155
<div
154156
className="AuthEntryBtn"
157+
data-testid="AuthEntryBtn"
155158
onClick={() => handleExpandDetail(ind)}
156159
>
157-
<div className="AuthEntryBtn__Title">
160+
<div
161+
className="AuthEntryBtn__Title"
162+
data-testid="AuthEntryBtn__Title"
163+
>
158164
<Icon.CodeCircle01 />
159165
{renderDetailTitle(detail)}
160166
</div>
@@ -163,7 +169,7 @@ export const AuthEntries = ({ invocations }: AuthEntriesProps) => {
163169
/>
164170
</div>
165171
{expandedIndex === ind ? (
166-
<div className="AuthEntryContent">
172+
<div className="AuthEntryContent" data-testid="AuthEntryContent">
167173
{renderDetailContent(detail)}
168174
</div>
169175
) : null}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import React from "react";
2+
import { render, waitFor, screen, fireEvent } from "@testing-library/react";
3+
import { Address, Keypair, ScInt, StrKey, xdr } from "stellar-sdk";
4+
5+
import { mockAccounts, TEST_PUBLIC_KEY, Wrapper } from "popup/__testHelpers__";
6+
import { AuthEntries } from "../AuthEntry";
7+
import * as internalApi from "@shared/api/internal";
8+
import { APPLICATION_STATE } from "@shared/constants/applicationState";
9+
import {
10+
TESTNET_NETWORK_DETAILS,
11+
DEFAULT_NETWORKS,
12+
} from "@shared/constants/stellar";
13+
import { ROUTES } from "popup/constants/routes";
14+
15+
describe("AuthEntry", () => {
16+
afterAll(() => {
17+
jest.clearAllMocks();
18+
});
19+
20+
const getContractSpecSpy = jest
21+
.spyOn(internalApi, "getContractSpec")
22+
.mockImplementation(() => {
23+
return Promise.resolve({
24+
definitions: {
25+
create: {
26+
properties: {
27+
args: ["admin"],
28+
},
29+
},
30+
},
31+
});
32+
});
33+
34+
it("renders auth entries for create contract v1", async () => {
35+
const assetCode = "KHL1";
36+
const assetType = new xdr.AlphaNum4({
37+
assetCode: Buffer.from(assetCode),
38+
issuer: Keypair.fromPublicKey(TEST_PUBLIC_KEY).xdrAccountId(),
39+
});
40+
41+
const args = new xdr.CreateContractArgs({
42+
contractIdPreimage: xdr.ContractIdPreimage.contractIdPreimageFromAsset(
43+
xdr.Asset.assetTypeCreditAlphanum4(assetType),
44+
),
45+
executable: xdr.ContractExecutable.contractExecutableStellarAsset(),
46+
});
47+
48+
const authorizedFn =
49+
xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeCreateContractHostFn(
50+
args,
51+
);
52+
const authorizedInvocation = new xdr.SorobanAuthorizedInvocation({
53+
function: authorizedFn,
54+
subInvocations: [],
55+
});
56+
57+
render(
58+
<Wrapper
59+
routes={[ROUTES.reviewAuthorization]}
60+
state={{
61+
auth: {
62+
error: null,
63+
applicationState: APPLICATION_STATE.PASSWORD_CREATED,
64+
TEST_PUBLIC_KEY,
65+
allAccounts: mockAccounts,
66+
hasPrivateKey: true,
67+
},
68+
settings: {
69+
networkDetails: TESTNET_NETWORK_DETAILS,
70+
networksList: DEFAULT_NETWORKS,
71+
isSorobanPublicEnabled: true,
72+
isRpcHealthy: true,
73+
},
74+
}}
75+
>
76+
<AuthEntries invocations={[authorizedInvocation]} />
77+
</Wrapper>,
78+
);
79+
await waitFor(() => screen.getAllByTestId("AuthEntryContainer"));
80+
await fireEvent.click(screen.getByTestId("AuthEntryBtn"));
81+
await waitFor(() => screen.getAllByTestId("AuthEntryContent"));
82+
83+
expect(screen.getByTestId("AuthEntryBtn__Title")).toHaveTextContent(
84+
"Contract creation",
85+
);
86+
87+
expect(getContractSpecSpy).not.toHaveBeenCalled();
88+
});
89+
90+
it("renders auth entries for create contract v2", async () => {
91+
const assetCode = "KHL1";
92+
const assetType = new xdr.AlphaNum4({
93+
assetCode: Buffer.from(assetCode),
94+
issuer: Keypair.fromPublicKey(TEST_PUBLIC_KEY).xdrAccountId(),
95+
});
96+
97+
const args = new xdr.CreateContractArgsV2({
98+
contractIdPreimage: xdr.ContractIdPreimage.contractIdPreimageFromAsset(
99+
xdr.Asset.assetTypeCreditAlphanum4(assetType),
100+
),
101+
executable: xdr.ContractExecutable.contractExecutableStellarAsset(),
102+
constructorArgs: [new Address(TEST_PUBLIC_KEY).toScVal()],
103+
});
104+
105+
const authorizedFn =
106+
xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeCreateContractV2HostFn(
107+
args,
108+
);
109+
const authorizedInvocation = new xdr.SorobanAuthorizedInvocation({
110+
function: authorizedFn,
111+
subInvocations: [],
112+
});
113+
114+
render(
115+
<Wrapper
116+
routes={[ROUTES.reviewAuthorization]}
117+
state={{
118+
auth: {
119+
error: null,
120+
applicationState: APPLICATION_STATE.PASSWORD_CREATED,
121+
TEST_PUBLIC_KEY,
122+
allAccounts: mockAccounts,
123+
hasPrivateKey: true,
124+
},
125+
settings: {
126+
networkDetails: TESTNET_NETWORK_DETAILS,
127+
networksList: DEFAULT_NETWORKS,
128+
isSorobanPublicEnabled: true,
129+
isRpcHealthy: true,
130+
},
131+
}}
132+
>
133+
<AuthEntries invocations={[authorizedInvocation]} />
134+
</Wrapper>,
135+
);
136+
await waitFor(() => screen.getAllByTestId("AuthEntryContainer"));
137+
await fireEvent.click(screen.getByTestId("AuthEntryBtn"));
138+
await waitFor(() => screen.getAllByTestId("AuthEntryContent"));
139+
140+
expect(screen.getByTestId("AuthEntryBtn__Title")).toHaveTextContent(
141+
"Contract creation",
142+
);
143+
144+
expect(getContractSpecSpy).not.toHaveBeenCalled();
145+
146+
const parameterKeys = screen.getAllByTestId("ParameterKey");
147+
const parameterValues = screen.getAllByTestId("ParameterValue");
148+
149+
expect(parameterKeys).toHaveLength(1);
150+
expect(parameterKeys[0]).toHaveTextContent("");
151+
152+
expect(parameterValues).toHaveLength(1);
153+
expect(parameterValues[0]).toHaveTextContent(TEST_PUBLIC_KEY);
154+
});
155+
156+
it("renders auth entries for invoke contract args", async () => {
157+
const CONTRACT = "CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE";
158+
const args = new xdr.InvokeContractArgs({
159+
functionName: Buffer.from("transfer"),
160+
args: [
161+
new Address(TEST_PUBLIC_KEY).toScVal(),
162+
new Address(TEST_PUBLIC_KEY).toScVal(),
163+
new ScInt(100).toI128(),
164+
],
165+
contractAddress: xdr.ScAddress.scAddressTypeContract(
166+
StrKey.decodeContract(CONTRACT) as any,
167+
),
168+
});
169+
170+
const authorizedFn =
171+
xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
172+
args,
173+
);
174+
const authorizedInvocation = new xdr.SorobanAuthorizedInvocation({
175+
function: authorizedFn,
176+
subInvocations: [],
177+
});
178+
179+
render(
180+
<Wrapper
181+
routes={[ROUTES.reviewAuthorization]}
182+
state={{
183+
auth: {
184+
error: null,
185+
applicationState: APPLICATION_STATE.PASSWORD_CREATED,
186+
TEST_PUBLIC_KEY,
187+
allAccounts: mockAccounts,
188+
hasPrivateKey: true,
189+
},
190+
settings: {
191+
networkDetails: TESTNET_NETWORK_DETAILS,
192+
networksList: DEFAULT_NETWORKS,
193+
isSorobanPublicEnabled: true,
194+
isRpcHealthy: true,
195+
},
196+
}}
197+
>
198+
<AuthEntries invocations={[authorizedInvocation]} />
199+
</Wrapper>,
200+
);
201+
await waitFor(() => screen.getAllByTestId("AuthEntryContainer"));
202+
await fireEvent.click(screen.getByTestId("AuthEntryBtn"));
203+
await waitFor(() => screen.getAllByTestId("AuthEntryContent"));
204+
205+
expect(screen.getByTestId("AuthEntryBtn__Title")).toHaveTextContent(
206+
"transfer",
207+
);
208+
209+
expect(getContractSpecSpy).not.toHaveBeenCalled();
210+
211+
const parameterKeys = screen.getAllByTestId("ParameterKey");
212+
const parameterValues = screen.getAllByTestId("ParameterValue");
213+
214+
expect(parameterKeys).toHaveLength(3);
215+
expect(parameterKeys[0]).toHaveTextContent("");
216+
expect(parameterKeys[1]).toHaveTextContent("");
217+
expect(parameterKeys[2]).toHaveTextContent("");
218+
219+
expect(parameterValues).toHaveLength(3);
220+
expect(parameterValues[0]).toHaveTextContent(TEST_PUBLIC_KEY);
221+
});
222+
});

extension/src/popup/components/signTransaction/Operations/KeyVal/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,13 @@ export const KeyValueInvokeHostFnArgs = ({
380380
contractId,
381381
fnName,
382382
showHeader = true,
383+
isAuthEntry = false,
383384
}: {
384385
args: xdr.ScVal[];
385386
contractId?: string;
386387
fnName?: string;
387388
showHeader?: boolean;
389+
isAuthEntry?: boolean;
388390
}) => {
389391
const [isLoading, setLoading] = React.useState(true);
390392
const [argNames, setArgNames] = React.useState([] as string[]);
@@ -405,12 +407,12 @@ export const KeyValueInvokeHostFnArgs = ({
405407
}
406408
}
407409

408-
if (contractId && fnName) {
410+
if (contractId && fnName && !isAuthEntry) {
409411
getSpec(contractId, fnName);
410412
} else {
411413
setLoading(false);
412414
}
413-
}, [contractId, fnName, networkDetails]);
415+
}, [contractId, fnName, networkDetails, isAuthEntry]);
414416

415417
return isLoading ? (
416418
<div className="Operations__pair--invoke" data-testid="OperationKeyVal">

0 commit comments

Comments
 (0)