diff --git a/apps/devtool/src/app/data-store/_components/DataStoreConfig.tsx b/apps/devtool/src/app/data-store/_components/DataStoreConfig.tsx index 295e4ff82..78a35da39 100644 --- a/apps/devtool/src/app/data-store/_components/DataStoreConfig.tsx +++ b/apps/devtool/src/app/data-store/_components/DataStoreConfig.tsx @@ -33,7 +33,7 @@ const DataStoreConfig = () => { useDataStoreApi() const [codeEditor, setCodeEditor] = useState() - const [displayCodeEditor, setDisplayCodeEditor] = useState(false) + const [displayCodeEditor, setDisplayCodeEditor] = useState(true) const [isDialogOpen, setIsDialogOpen] = useState(false) useEffect(() => { diff --git a/apps/devtool/src/app/request-playground/_components/PlaygroundEditor.tsx b/apps/devtool/src/app/request-playground/_components/PlaygroundEditor.tsx index 673f6ba9f..ab8f403c6 100644 --- a/apps/devtool/src/app/request-playground/_components/PlaygroundEditor.tsx +++ b/apps/devtool/src/app/request-playground/_components/PlaygroundEditor.tsx @@ -12,7 +12,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Editor } from '@monaco-editor/react' import { Decision, EvaluationResponse } from '@narval/policy-engine-shared' import { hash } from '@narval/signature' -import axios from 'axios' +import axios, { AxiosError } from 'axios' import { useMemo, useRef, useState } from 'react' import NarButton from '../../_design-system/NarButton' import useAccountSignature from '../../_hooks/useAccountSignature' @@ -22,27 +22,30 @@ import example from './example.json' const PlaygroundEditor = () => { const { engineUrl, engineClientId, engineClientSecret, vaultUrl, vaultClientId } = useStore() const { jwk, signAccountJwsd, signAccountJwt } = useAccountSignature() - const [data, setData] = useState(JSON.stringify(example, null, 2)) + const [codeEditor, setCodeEditor] = useState(JSON.stringify(example, null, 2)) const [isProcessing, setIsProcessing] = useState(false) const [evaluationResponse, setEvaluationResponse] = useState() const [signature, setSignature] = useState() + const [error, setError] = useState() const editorRef = useRef(null) const monacoRef = useRef(null) const canBeSigned = useMemo(() => { + if (!codeEditor || !evaluationResponse) return false + try { - const transactionRequest = JSON.parse(data || '{}') - return transactionRequest?.authentication && evaluationResponse?.decision === Decision.PERMIT + const transactionRequest = JSON.parse(codeEditor) + return transactionRequest.authentication && evaluationResponse.decision === Decision.PERMIT } catch (error) { return false } - }, [data, evaluationResponse]) + }, [codeEditor, evaluationResponse]) const getApprovalSignature = async () => { - if (!data) return + if (!codeEditor) return - const transactionRequest = JSON.parse(data) + const transactionRequest = JSON.parse(codeEditor) const payload = { iss: 'fe723044-35df-4e99-9739-122a48d4ab96', @@ -56,12 +59,15 @@ const PlaygroundEditor = () => { } const sendEvaluation = async () => { - if (!data || !jwk) return + if (!codeEditor || !jwk) return setIsProcessing(true) + setEvaluationResponse(undefined) + setSignature(undefined) + setError(undefined) try { - const transactionRequest = JSON.parse(data) + const transactionRequest = JSON.parse(codeEditor) const payload = { iss: 'fe723044-35df-4e99-9739-122a48d4ab96', @@ -82,7 +88,7 @@ const PlaygroundEditor = () => { } ) - setData( + setCodeEditor( JSON.stringify( { ...transactionRequest, @@ -93,8 +99,10 @@ const PlaygroundEditor = () => { ) ) setEvaluationResponse(evaluation.data) - } catch (error) { - console.log(error) + } catch (err) { + const error = err as AxiosError + const errorData = error.response?.data as any + setError(errorData?.message || error.message) } setIsProcessing(false) @@ -107,6 +115,10 @@ const PlaygroundEditor = () => { if (!accessToken?.value || !request) return + setEvaluationResponse(undefined) + setSignature(undefined) + setError(undefined) + try { const bodyPayload = { request } @@ -135,8 +147,8 @@ const PlaygroundEditor = () => { setData(value)} + value={codeEditor} + onChange={(value) => setCodeEditor(value)} onMount={(editor, monaco) => { editorRef.current = editor monacoRef.current = monaco @@ -157,8 +169,10 @@ const PlaygroundEditor = () => { onClick={signRequest} disabled={isProcessing || !canBeSigned} /> - } onClick={getApprovalSignature} /> - {!isProcessing && evaluationResponse && ( + {false && ( + } onClick={getApprovalSignature} /> + )} + {!isProcessing && !error && evaluationResponse && (
{evaluationResponse.decision === Decision.PERMIT && ( @@ -173,12 +187,13 @@ const PlaygroundEditor = () => {
)} - {!isProcessing && evaluationResponse && ( + {!isProcessing && error &&
{error}
} + {!isProcessing && !error && evaluationResponse && (
{JSON.stringify(evaluationResponse, null, 3)}
)} - {!isProcessing && signature &&
{signature}
} + {!isProcessing && !error && signature &&
{signature}
} ) diff --git a/apps/devtool/src/app/request-playground/_components/accumulation.json b/apps/devtool/src/app/request-playground/_components/accumulation.json index e69de29bb..cc4d64260 100644 --- a/apps/devtool/src/app/request-playground/_components/accumulation.json +++ b/apps/devtool/src/app/request-playground/_components/accumulation.json @@ -0,0 +1,40 @@ +{ + "request": { + "resourceId": "eip155:eoa:0x494042504a8148a6d00ab10ed26043f5579ce00f", + "action": "signTransaction", + "nonce": "6bb2b3e9-fa8a-4081-a837-575184ceb3a5", + "transactionRequest": { + "from": "0xed123cf8e3ba51c6c15da1eac74b2b5deea31448", + "to": "0x031d8c0ca142921c459bcb28104c0ff37928f9ed", + "value": "0xde0b6b3a7640000", + "chainId": 137, + "type": "2" + } + }, + "feeds": [ + { + "source": "armory/price-feed", + "sig": "eyJhbGciOiJFSVAxOTEiLCJraWQiOiIweDlENDMyYTA5Q0JmNTVGMjJBYTZhMkUyOTBhY0IxMkQ1N2QyOUIyRmMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJmZTcyMzA0NC0zNWRmLTRlOTktOTczOS0xMjJhNDhkNGFiOTYiLCJyZXF1ZXN0SGFzaCI6IjB4ZjdmY2MyMzRhMTMzNWNmNGE0NDE0MzAwNWJhOWJhNWQyY2VlMTJhMmZmZDFlNDMyYTU4Yjc5YjllNzcyYzk5NiIsInN1YiI6ImVpcDE1NTplb2E6MHg0OTQwNDI1MDRhODE0OGE2ZDAwYWIxMGVkMjYwNDNmNTU3OWNlMDBmIn0.BxgEr9TILTIocaNpQs-59vKhBSePpS-q0D4VWfVpqIs0bRSBp8vBMHkKa7AxdtfMwRCBd86vldj-1Ebb5UtmMhs", + "data": { + "eip155:137/slip44:966": { + "fiat:usd": "0.99", + "fiat:eur": "1.10" + } + } + }, + { + "source": "armory/historical-transfer-feed", + "sig": "eyJhbGciOiJFSVAxOTEiLCJraWQiOiIweDlENDMyYTA5Q0JmNTVGMjJBYTZhMkUyOTBhY0IxMkQ1N2QyOUIyRmMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJmZTcyMzA0NC0zNWRmLTRlOTktOTczOS0xMjJhNDhkNGFiOTYiLCJyZXF1ZXN0SGFzaCI6IjB4ZjdmY2MyMzRhMTMzNWNmNGE0NDE0MzAwNWJhOWJhNWQyY2VlMTJhMmZmZDFlNDMyYTU4Yjc5YjllNzcyYzk5NiIsInN1YiI6ImVpcDE1NTplb2E6MHg0OTQwNDI1MDRhODE0OGE2ZDAwYWIxMGVkMjYwNDNmNTU3OWNlMDBmIn0.BxgEr9TILTIocaNpQs-59vKhBSePpS-q0D4VWfVpqIs0bRSBp8vBMHkKa7AxdtfMwRCBd86vldj-1Ebb5UtmMhs", + "data": [ + { + "amount": "500000000000000000", + "from": "eip155:eoa:0x494042504a8148a6d00ab10ed26043f5579ce00f", + "token": "eip155:137/slip44:966", + "rates": { "fiat:usd": "0.90", "fiat:eur": "1.10" }, + "chainId": 137, + "initiatedBy": "61e775a9-5f68-41ab-a775-5806845e6e72" + } + ] + } + ] +} diff --git a/apps/policy-engine/src/open-policy-agent/core/type/open-policy-agent.type.ts b/apps/policy-engine/src/open-policy-agent/core/type/open-policy-agent.type.ts index 980f52663..1da76877a 100644 --- a/apps/policy-engine/src/open-policy-agent/core/type/open-policy-agent.type.ts +++ b/apps/policy-engine/src/open-policy-agent/core/type/open-policy-agent.type.ts @@ -4,6 +4,7 @@ import { Action, Address, CredentialEntity, + Feed, HistoricalTransfer, TransactionRequest, UserRole @@ -25,6 +26,7 @@ export type Input = { resource?: { uid: string } approvals?: CredentialEntity[] transfers?: HistoricalTransfer[] + feeds?: Feed[] } // TODO: (@wcalderipe, 18/03/24) Check with @samteb how can we replace these diff --git a/apps/policy-engine/src/open-policy-agent/core/util/evaluation.util.ts b/apps/policy-engine/src/open-policy-agent/core/util/evaluation.util.ts index 1d31025f8..d95736655 100644 --- a/apps/policy-engine/src/open-policy-agent/core/util/evaluation.util.ts +++ b/apps/policy-engine/src/open-policy-agent/core/util/evaluation.util.ts @@ -3,6 +3,7 @@ import { CredentialEntity, Entities, EvaluationRequest, + Feed, Request, SignMessageAction, SignRawAction, @@ -15,9 +16,14 @@ import { indexBy } from 'lodash/fp' import { OpenPolicyAgentException } from '../exception/open-policy-agent.exception' import { Data, Input, UserGroup, WalletGroup } from '../type/open-policy-agent.type' -type Mapping = (request: R, principal: CredentialEntity, approvals?: CredentialEntity[]) => Input +type Mapping = ( + request: R, + principal: CredentialEntity, + approvals?: CredentialEntity[], + feeds?: Feed[] +) => Input -const toSignTransaction: Mapping = (request, principal, approvals): Input => { +const toSignTransaction: Mapping = (request, principal, approvals, feeds): Input => { const result = safeDecode({ input: { type: InputType.TRANSACTION_REQUEST, @@ -32,7 +38,8 @@ const toSignTransaction: Mapping = (request, principal, a approvals, intent: result.intent, transactionRequest: request.transactionRequest, - resource: { uid: request.resourceId } + resource: { uid: request.resourceId }, + feeds } } @@ -105,8 +112,25 @@ export const toInput = (params: { ]) const mapper = mappers.get(action) + // For demo purpose, we need to modify timestamps of transaction + // and fake it that those happened in the last 24hours + + // const feedsDemo = evaluation.feeds?.map((feed) => { + // if (feed.source === 'armory/historical-transfer-feed') { + // const { data, ...res } = feed + // const dataRes = (data as any[]).map((d: any) => ({ + // ...d, + // timestamp: new Date().getTime() - 10 * 60 * 60 * 1000 + // })) + + // return { ...res, data: dataRes } + // } + + // return feed + // }) as Feed[] + if (mapper) { - return mapper(evaluation.request, params.principal, params.approvals) + return mapper(evaluation.request, params.principal, params.approvals, evaluation.feeds) } throw new OpenPolicyAgentException({ diff --git a/packages/policy-engine-shared/src/lib/type/domain.type.ts b/packages/policy-engine-shared/src/lib/type/domain.type.ts index 4a7d20397..c5175469a 100644 --- a/packages/policy-engine-shared/src/lib/type/domain.type.ts +++ b/packages/policy-engine-shared/src/lib/type/domain.type.ts @@ -96,7 +96,7 @@ export const Feed = (dataSchema: Data) => z.object({ source: z.string(), sig: JwtString.nullable(), - data: dataSchema + data: dataSchema.optional() }) /** @@ -116,7 +116,7 @@ export type Feed = { * any trusted data sources if they prefer. */ sig: JwtString | null - data: Data + data?: Data } export const EvaluationRequest = z