Skip to content

Commit 1df8833

Browse files
authored
feat: reorder arguments in tx-link (#723)
1 parent 150f149 commit 1df8833

File tree

7 files changed

+190
-62
lines changed

7 files changed

+190
-62
lines changed

packages/adena-extension/src/common/provider/gno/gno-provider.ts

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,15 @@ import {
1212
newRequest,
1313
parseABCI,
1414
RPCResponse,
15+
stringToBase64,
1516
TransactionEndpoint,
1617
Tx,
1718
uint8ArrayToBase64,
1819
} from '@gnolang/tm2-js-client';
1920
import axios from 'axios';
2021
import { ResponseDeliverTx } from './proto/tm2/abci';
21-
import { parseProto } from './utils';
22-
23-
interface ABCIAccount {
24-
BaseAccount: {
25-
address: string;
26-
coins: string;
27-
public_key: {
28-
'@type': string;
29-
value: string;
30-
} | null;
31-
account_number: string;
32-
sequence: string;
33-
};
34-
}
35-
36-
export interface AccountInfo {
37-
address: string;
38-
coins: string;
39-
chainId: string;
40-
status: 'ACTIVE' | 'IN_ACTIVE';
41-
publicKey: {
42-
'@type': string;
43-
value: string;
44-
} | null;
45-
accountNumber: string;
46-
sequence: string;
47-
}
22+
import { ABCIAccount, AccountInfo, GnoDocumentInfo, VMQueryType } from './types';
23+
import { fetchABCIResponse, makeRequestQueryPath, parseProto, postABCIResponse } from './utils';
4824

4925
export class GnoProvider extends GnoJSONRPCProvider {
5026
private chainId?: string;
@@ -67,25 +43,14 @@ export class GnoProvider extends GnoJSONRPCProvider {
6743
accountNumber: '0',
6844
sequence: '0',
6945
};
70-
const params = {
71-
request: newRequest(ABCIEndpoint.ABCI_QUERY, [
72-
`auth/accounts/${address}`,
73-
'',
74-
`${height ?? 0}`,
75-
false,
76-
]),
77-
};
46+
const requestBody = newRequest(ABCIEndpoint.ABCI_QUERY, [
47+
`auth/accounts/${address}`,
48+
'',
49+
`${height ?? 0}`,
50+
false,
51+
]);
7852

79-
const abciResponse = await fetch(this.baseURL, {
80-
method: 'POST',
81-
headers: {
82-
'Content-Type': 'application/json',
83-
},
84-
body: JSON.stringify(params.request),
85-
})
86-
.then((res) => res.json())
87-
.then((data) => data as RPCResponse<ABCIResponse>)
88-
.catch(() => null);
53+
const abciResponse = await postABCIResponse(this.baseURL, requestBody).catch(() => null);
8954

9055
const abciData = abciResponse?.result?.response.ResponseBase.Data;
9156
// Make sure the response is initialized
@@ -213,4 +178,28 @@ export class GnoProvider extends GnoJSONRPCProvider {
213178
return response.gasUsed.toInt();
214179
});
215180
}
181+
182+
public async getRealmDocument(packagePath: string): Promise<GnoDocumentInfo | null> {
183+
const query = VMQueryType.QUERY_DOCUMENT;
184+
const base64PackagePath = stringToBase64(packagePath);
185+
const requestQuery = this.makeRequestQueryPath(query, base64PackagePath);
186+
187+
try {
188+
const abciResponse = await fetchABCIResponse(requestQuery, false);
189+
const abciData = abciResponse?.result?.response.ResponseBase.Data;
190+
if (!abciData) {
191+
return null;
192+
}
193+
194+
return parseABCI<GnoDocumentInfo>(abciData);
195+
} catch (e) {
196+
console.info(e);
197+
}
198+
199+
return null;
200+
}
201+
202+
private makeRequestQueryPath(path: string, data: string): string {
203+
return makeRequestQueryPath(this.baseURL, path, data);
204+
}
216205
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './gno-provider';
2+
export * from './types';
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
export enum VMQueryType {
2+
QUERY_DOCUMENT = 'vm/qdoc',
3+
QUERY_VALUE = 'vm/qval',
4+
}
5+
6+
export interface ABCIAccount {
7+
BaseAccount: {
8+
address: string;
9+
coins: string;
10+
public_key: {
11+
'@type': string;
12+
value: string;
13+
} | null;
14+
account_number: string;
15+
sequence: string;
16+
};
17+
}
18+
19+
export interface AccountInfo {
20+
address: string;
21+
coins: string;
22+
chainId: string;
23+
status: 'ACTIVE' | 'IN_ACTIVE';
24+
publicKey: {
25+
'@type': string;
26+
value: string;
27+
} | null;
28+
accountNumber: string;
29+
sequence: string;
30+
}
31+
32+
export interface GnoDocumentInfo {
33+
package_path: string;
34+
package_line: string;
35+
package_doc: string;
36+
values: GnoPackageValue[];
37+
funcs: GnoFunction[];
38+
}
39+
40+
export interface GnoPackageValue {
41+
signature: string;
42+
const: boolean;
43+
values: GnoDocumentValue[];
44+
doc: string;
45+
}
46+
47+
export interface GnoDocumentValue {
48+
name: string;
49+
doc: string;
50+
type: string;
51+
}
52+
53+
export interface GnoFunction {
54+
type: string;
55+
name: string;
56+
signature: string;
57+
doc: string;
58+
params: GnoFunctionParam[];
59+
results: GnoFunctionParam[];
60+
}
61+
62+
export interface GnoFunctionParam {
63+
name: string;
64+
type: string;
65+
}

packages/adena-extension/src/common/provider/gno/utils.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BinaryReader } from '@bufbuild/protobuf/wire';
2+
import { ABCIResponse, RPCRequest, RPCResponse } from '@gnolang/tm2-js-client';
23

34
export const parseProto = <T>(
45
data: string | Uint8Array,
@@ -9,3 +10,42 @@ export const parseProto = <T>(
910

1011
return protoData;
1112
};
13+
14+
export const fetchABCIResponse = async (
15+
url: string,
16+
withCache?: boolean,
17+
): Promise<RPCResponse<ABCIResponse>> => {
18+
const response = await fetch(url, {
19+
cache: withCache ? 'force-cache' : 'default',
20+
});
21+
const data = await response.json();
22+
return data;
23+
};
24+
25+
export const postABCIResponse = async (
26+
url: string,
27+
body: RPCRequest,
28+
): Promise<RPCResponse<ABCIResponse>> => {
29+
const response = await fetch(url, {
30+
method: 'POST',
31+
headers: {
32+
'Content-Type': 'application/json',
33+
},
34+
body: JSON.stringify(body),
35+
});
36+
const data = await response.json();
37+
return data;
38+
};
39+
40+
export const makeRequestQueryPath = (baseUrl: string, path: string, data: string): string => {
41+
const requestUri = `${baseUrl}/abci_query?path="${path}"&data="${data}"`;
42+
43+
if (baseUrl.startsWith('http') || baseUrl.startsWith('https')) {
44+
return requestUri;
45+
}
46+
47+
const isLocal = baseUrl.startsWith('localhost') || baseUrl.startsWith('127.0.0.1');
48+
const protocol = isLocal ? 'http' : 'https';
49+
50+
return `${protocol}://${requestUri}`;
51+
};

packages/adena-extension/src/inject/message/command-handler.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { WalletResponseFailureType, WalletResponseSuccessType } from '@adena-wallet/sdk';
22
import { DEFAULT_GAS_WANTED } from '@common/constants/tx.constant';
3+
import { GnoDocumentInfo } from '@common/provider/gno';
4+
import { GnoProvider } from '@common/provider/gno/gno-provider';
35
import { MemoryProvider } from '@common/provider/memory/memory-provider';
46
import { AdenaExecutor } from '@inject/executor';
57
import { ContractMessage, TransactionParams } from '@inject/types';
@@ -12,6 +14,7 @@ import {
1214
} from './commands/encrypt';
1315
import { clearPopup } from './commands/popup';
1416
import {
17+
GnoArgumentInfo,
1518
GnoConnectInfo,
1619
GnoMessageInfo,
1720
parseGnoConnectInfo,
@@ -120,10 +123,25 @@ export class CommandHandler {
120123
return;
121124
}
122125

123-
// Make TransactionParams
124-
const transactionParams = makeTransactionMessage(gnoMessageInfo, gnoConnectInfo);
126+
const gnoProvider = new GnoProvider(gnoConnectInfo.rpc, gnoConnectInfo.chainId);
127+
const realmDocument = await gnoProvider.getRealmDocument(gnoMessageInfo.packagePath);
128+
if (!realmDocument) {
129+
console.info('Realm document not found');
130+
return;
131+
}
125132

126-
executor.doContract(transactionParams).then(console.info).catch(console.error);
133+
try {
134+
// Make TransactionParams
135+
const transactionParams = makeTransactionMessage(
136+
gnoMessageInfo,
137+
gnoConnectInfo,
138+
realmDocument,
139+
);
140+
141+
executor.doContract(transactionParams).then(console.info);
142+
} catch (error) {
143+
console.info(error);
144+
}
127145
};
128146
}
129147

@@ -145,11 +163,27 @@ function makeInternalErrorResponse(message: CommandMessageData): CommandMessageD
145163
function makeTransactionMessage(
146164
gnoMessageInfo: GnoMessageInfo,
147165
gnoConnectInfo: GnoConnectInfo,
166+
realmDocument: GnoDocumentInfo,
148167
): TransactionParams & { gasFee: number; gasWanted: number } {
149-
const args =
150-
gnoMessageInfo.args?.map((arg) => {
151-
return arg.value;
152-
}) || [];
168+
const func = realmDocument.funcs.find((f) => f.name === gnoMessageInfo.functionName);
169+
if (!func) {
170+
throw new Error(`Function not found: ${gnoMessageInfo.functionName}`);
171+
}
172+
173+
const gnoArguments: GnoArgumentInfo[] = func.params.map((param, index) => {
174+
const arg = gnoMessageInfo.args?.find((arg) => arg.key === param.name);
175+
const value = arg?.value || '';
176+
177+
return {
178+
index,
179+
key: param.name,
180+
value,
181+
};
182+
});
183+
184+
const messageArguments = gnoArguments.map((arg) => {
185+
return arg.value;
186+
});
153187

154188
const messages: ContractMessage[] = [
155189
{
@@ -159,7 +193,7 @@ function makeTransactionMessage(
159193
send: gnoMessageInfo.send,
160194
pkg_path: gnoMessageInfo.packagePath,
161195
func: gnoMessageInfo.functionName,
162-
args,
196+
args: messageArguments,
163197
},
164198
},
165199
];
@@ -172,6 +206,6 @@ function makeTransactionMessage(
172206
chainId: gnoConnectInfo.chainId,
173207
rpcUrl: gnoConnectInfo.rpc,
174208
},
175-
arguments: gnoMessageInfo.args,
209+
arguments: gnoArguments,
176210
};
177211
}

packages/adena-extension/src/inject/message/methods/gno-connect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export function parseGnoConnectInfo(): GnoConnectInfo | null {
7878
* https://gno.land/r/demo/boards$help&func=CreateThread&bid=2&send=100ugnot
7979
* - $help acts as a marker to split the pathname.
8080
* - func= specifies functionName.
81-
* - send= specifies the amount to send.
81+
* - .send= specifies the amount to send.
8282
* - other parameters are collected in the args array.
8383
*
8484
* @returns GnoMessageInfo object (packagePath, functionName, send, args)
@@ -128,7 +128,7 @@ export function parseGnoMessageInfo(href: string): GnoMessageInfo | null {
128128
continue;
129129
}
130130

131-
if (key === 'send') {
131+
if (key === '.send') {
132132
messageInfo.send = value || '';
133133
continue;
134134
}

packages/adena-extension/src/services/wallet/wallet-account.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AccountInfo, GnoProvider } from '@common/provider/gno/gno-provider';
1+
import { AccountInfo, GnoProvider } from '@common/provider/gno';
22
import { WalletAccountRepository } from '@repositories/wallet';
33
import { Account } from 'adena-module';
44

@@ -83,11 +83,9 @@ export class WalletAccountService {
8383
return this.walletAccountRepository.getAccountNames();
8484
};
8585

86-
public updateAccountNames = async (
87-
accountNames: {
88-
[key in string]: string;
89-
},
90-
): Promise<boolean> => {
86+
public updateAccountNames = async (accountNames: {
87+
[key in string]: string;
88+
}): Promise<boolean> => {
9189
return this.walletAccountRepository.updateAccountNames(accountNames);
9290
};
9391

0 commit comments

Comments
 (0)