updater
This commit is contained in:
parent
27da69f1d2
commit
6c4d382625
@ -47,8 +47,8 @@
|
|||||||
},
|
},
|
||||||
"_scale": {
|
"_scale": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0.805834949016571,
|
"x": 0.9920991955598369,
|
||||||
"y": 0.805834949016571,
|
"y": 0.9920991955598369,
|
||||||
"z": 1
|
"z": 1
|
||||||
},
|
},
|
||||||
"_quat": {
|
"_quat": {
|
||||||
@ -13797,7 +13797,7 @@
|
|||||||
"__id__": 411
|
"__id__": 411
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": false,
|
"_active": true,
|
||||||
"_level": 2,
|
"_level": 2,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
|
File diff suppressed because one or more lines are too long
@ -24,34 +24,42 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
package org.cocos2dx.javascript;
|
package org.cocos2dx.javascript;
|
||||||
|
|
||||||
import org.cocos2dx.lib.Cocos2dxActivity;
|
|
||||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
|
|
||||||
import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.walletconnect.Session;
|
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Looper;
|
import android.net.Uri;
|
||||||
import android.widget.Toast;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter;
|
||||||
|
import com.squareup.moshi.Moshi;
|
||||||
import com.youme.voiceengine.MemberChange;
|
import com.youme.voiceengine.MemberChange;
|
||||||
import com.youme.voiceengine.YouMeCallBackInterface;
|
import com.youme.voiceengine.YouMeCallBackInterface;
|
||||||
import com.youme.voiceengine.YouMeConst;
|
import com.youme.voiceengine.YouMeConst;
|
||||||
import com.youme.voiceengine.api;
|
import com.youme.voiceengine.api;
|
||||||
import com.youme.voiceengine.mgr.YouMeManager;
|
import com.youme.voiceengine.mgr.YouMeManager;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import org.cocos2dx.javascript.wc.JWCSession;
|
||||||
|
import org.cocos2dx.javascript.wc.entity.CallResult;
|
||||||
|
import org.cocos2dx.javascript.wc.entity.ChainObj;
|
||||||
|
import org.cocos2dx.javascript.wc.entity.ChangeChainObj;
|
||||||
|
import org.cocos2dx.lib.Cocos2dxActivity;
|
||||||
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
|
||||||
|
import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.walletconnect.Session;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function1;
|
||||||
|
|
||||||
public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterface , Session.Callback {
|
public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterface , Session.Callback {
|
||||||
private static AppActivity appActivity = null;
|
private static AppActivity appActivity = null;
|
||||||
|
private static final String TAG = "AppActivity";
|
||||||
private static final String appKey="YOUME1838B3633FF1410BDC9124BBD806F245B9D2E5AC";
|
private static final String appKey="YOUME1838B3633FF1410BDC9124BBD806F245B9D2E5AC";
|
||||||
private static final String appSecret="q6B570yTyj/00Nk4mYZtgDwyew5v05t13V1vo4mxpEuAaWUiinAyVxG41sNu3vsFe8sipOLfKfIVYGhzpQrqzvj5sId3mrBfj/s65a2gp36yDrI/nX5BnUAJB317SEosR6xLoPuhBvHU+/1DWI7nKSKaRNxnQiC46PJKFc2kX50BAAE=";
|
private static final String appSecret="q6B570yTyj/00Nk4mYZtgDwyew5v05t13V1vo4mxpEuAaWUiinAyVxG41sNu3vsFe8sipOLfKfIVYGhzpQrqzvj5sId3mrBfj/s65a2gp36yDrI/nX5BnUAJB317SEosR6xLoPuhBvHU+/1DWI7nKSKaRNxnQiC46PJKFc2kX50BAAE=";
|
||||||
|
|
||||||
@ -182,41 +190,41 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
|||||||
|
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_OK: //YOUME_EVENT_INIT_OK:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_OK: //YOUME_EVENT_INIT_OK:
|
||||||
System.out.println("Talk 初始化成功");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_FAILED://YOUME_EVENT_INIT_FAILED:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_FAILED://YOUME_EVENT_INIT_FAILED:
|
||||||
System.out.println("Talk 初始化失败");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_OK://YOUME_EVENT_JOIN_OK:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_OK://YOUME_EVENT_JOIN_OK:
|
||||||
System.out.println("Talk 进入频道成功,频道:" + channelID + " 用户id:" + param);
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_FAILED://YOUME_EVENT_JOIN_FAILED:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_FAILED://YOUME_EVENT_JOIN_FAILED:
|
||||||
System.out.println("Talk 进入频道:" + channelID + "失败,code:" + errorCode);
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ONE://YOUME_EVENT_LEAVED_ONE:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ONE://YOUME_EVENT_LEAVED_ONE:
|
||||||
System.out.println("Talk 离开单个频道:" + channelID);
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ALL://YOUME_EVENT_LEAVED_ALL:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ALL://YOUME_EVENT_LEAVED_ALL:
|
||||||
System.out.println("Talk 离开所有频道,这个回调channel参数为空字符串");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_PAUSED://YOUME_EVENT_PAUSED:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_PAUSED://YOUME_EVENT_PAUSED:
|
||||||
System.out.println("Talk 暂停");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RESUMED://YOUME_EVENT_RESUMED:
|
case YouMeConst.YouMeEvent.YOUME_EVENT_RESUMED://YOUME_EVENT_RESUMED:
|
||||||
System.out.println("Talk 恢复");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_SUCCESS://YOUME_EVENT_SPEAK_SUCCESS:///< 切换对指定频道讲话成功(适用于多频道模式)
|
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_SUCCESS://YOUME_EVENT_SPEAK_SUCCESS:
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_FAILED://YOUME_EVENT_SPEAK_FAILED:///< 切换对指定频道讲话失败(适用于多频道模式)
|
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_FAILED://YOUME_EVENT_SPEAK_FAILED://
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTING://YOUME_EVENT_RECONNECTING:///< 断网了,正在重连
|
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTING://YOUME_EVENT_RECONNECTING:/
|
||||||
System.out.println("Talk 正在重连");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTED://YOUME_EVENT_RECONNECTED:///< 断网重连成功
|
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTED://YOUME_EVENT_RECONNECTED://
|
||||||
System.out.println("Talk 重连成功");
|
|
||||||
break;
|
break;
|
||||||
case YouMeConst.YouMeEvent.YOUME_EVENT_REC_PERMISSION_STATUS://YOUME_EVENT_REC_FAILED:///< 通知录音启动失败(此时不管麦克风mute状态如何,都没有声音输出)
|
case YouMeConst.YouMeEvent.YOUME_EVENT_REC_PERMISSION_STATUS://YOUME_EVENT_REC_FAILED://
|
||||||
System.out.println("录音启动失败,code:" + errorCode);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -249,9 +257,11 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
|||||||
public static void connectwallet(String data){
|
public static void connectwallet(String data){
|
||||||
ExampleApplication.Companion.resetSession();
|
ExampleApplication.Companion.resetSession();
|
||||||
ExampleApplication.session.addCallback(appActivity);
|
ExampleApplication.session.addCallback(appActivity);
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
String url = "metamask://wc?uri=" + ExampleApplication.config.toWCUri();
|
||||||
intent.setData(Uri.parse(ExampleApplication.config.toWCUri()));
|
// String url = "https://metamask.app.link/wc?uri="+ExampleApplication.config.toWCUri();
|
||||||
System.out.println(ExampleApplication.config.toWCUri());
|
Uri uri = Uri.parse(url);
|
||||||
|
Log.i(TAG, url);
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||||
try {
|
try {
|
||||||
appActivity.startActivity(intent);
|
appActivity.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
@ -264,15 +274,35 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
|||||||
// private boolean hasSign = false;
|
// private boolean hasSign = false;
|
||||||
|
|
||||||
public static void signApp(String nonce){
|
public static void signApp(String nonce){
|
||||||
ExampleApplication.Companion.ethSign(nonce,ExampleApplication.session.approvedAccounts().get(0));
|
Log.i(TAG, nonce);
|
||||||
|
List<String> paramList = new ArrayList<>();
|
||||||
|
paramList.add(ExampleApplication.session.approvedAccounts().get(0));
|
||||||
|
paramList.add(nonce);
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
ExampleApplication.session.performMethodCall(new Session.MethodCall.Custom(time, "eth_signTypedData", paramList), new Function1<Session.MethodCall.Response, Unit>() {
|
||||||
|
@Override
|
||||||
|
public Unit invoke(Session.MethodCall.Response resp) {
|
||||||
|
if (resp.getResult() != null) {
|
||||||
|
String signStr = Objects.requireNonNull(resp.getResult()).toString();
|
||||||
|
Log.i(TAG, signStr);
|
||||||
|
signStr = signStr.substring(2);
|
||||||
|
Cocos2dxJavascriptJavaBridge.evalString("window.signApp(\"" + signStr + "\")");
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "sign is empty");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
i.setData(Uri.parse("wc://"));
|
i.setData(Uri.parse("metamask://"));
|
||||||
appActivity.startActivity(i);
|
appActivity.startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void changeArea(String area){
|
public static void changeArea(String area){
|
||||||
api.unInit();
|
// api.unInit();
|
||||||
System.out.println("change area"+area);
|
System.out.println("change area"+area);
|
||||||
switch (area){
|
switch (area){
|
||||||
case "0":
|
case "0":
|
||||||
@ -298,57 +328,125 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMethodCall(@NotNull final Session.MethodCall methodCall) {
|
public void onMethodCall(@NotNull final Session.MethodCall methodCall) {
|
||||||
if(ExampleApplication.session.approvedAccounts()!=null){
|
|
||||||
if(methodCall.id()==999999999){
|
|
||||||
//签名
|
|
||||||
appActivity.runOnGLThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String tmp = ExampleApplication.Companion.getSignRes().substring(2);
|
|
||||||
System.out.println("签名无前缀"+tmp);
|
|
||||||
Cocos2dxJavascriptJavaBridge.evalString("window.signApp(\""+tmp+"\")");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
//连接钱包
|
|
||||||
appActivity.runOnGLThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String result = methodCall.toString();
|
|
||||||
String[] allRes = result.split(",");
|
|
||||||
for(int i=0;i<allRes.length;i++){
|
|
||||||
//删除所有空格
|
|
||||||
String tt = allRes[i].replaceAll("\\s+", "");
|
|
||||||
if(tt.startsWith("chainId")){
|
|
||||||
String[] fi = tt.split("=");
|
|
||||||
int chainid = Double.valueOf(fi[1]).intValue();
|
|
||||||
System.out.println("chainid---"+chainid);
|
|
||||||
if(chainid==321){
|
|
||||||
// 链正确
|
|
||||||
String tmp = ExampleApplication.session.approvedAccounts().get(0).substring(2);
|
|
||||||
Cocos2dxJavascriptJavaBridge.evalString("window.connectOK(\""+tmp+"\")");
|
|
||||||
}else{
|
|
||||||
// 链不正确
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
final Toast toast = Toast.makeText(appActivity, "Your wallet should support KCC chain!" , Toast.LENGTH_SHORT);
|
|
||||||
toast.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onStatus(@NotNull Session.Status status) {
|
public void onStatus(@NotNull Session.Status status) {
|
||||||
|
if (status.equals(Session.Status.Approved.INSTANCE)) {
|
||||||
|
sessionApproved();
|
||||||
|
} else if (status.equals(Session.Status.Closed.INSTANCE)){
|
||||||
|
Log.i(TAG, "Session.Status.Closed");
|
||||||
|
} else if (status.equals(Session.Status.Connected.INSTANCE)) {
|
||||||
|
Log.i(TAG, "Session.Status.Connected");
|
||||||
|
} else if (status.equals(Session.Status.Disconnected.INSTANCE)) {
|
||||||
|
Log.i(TAG, "Session.Status.Disconnected");
|
||||||
|
} else {
|
||||||
|
// ERROR
|
||||||
|
Log.e(TAG, "Session.Status.Error: " + status.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrMsg(String msg) {
|
||||||
|
runOnGLThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Cocos2dxJavascriptJavaBridge.evalString("window.changeChain()");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sessionApproved() {
|
||||||
|
List<String> accounts = ExampleApplication.session.approvedAccounts();
|
||||||
|
if (accounts == null || accounts.size() == 0) {
|
||||||
|
showErrMsg("Login failed, no account");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String account = accounts.get(0);
|
||||||
|
if ("".equals(account) || null == account || account.length() < 2) {
|
||||||
|
showErrMsg("Login failed, no account");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long chainId = ((JWCSession) ExampleApplication.session).chainId();
|
||||||
|
if (chainId == null) {
|
||||||
|
showErrMsg("Login failed, no chainId");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (chainId != 321L) {
|
||||||
|
appActivity.runOnGLThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Cocos2dxJavascriptJavaBridge.evalString("window.chainErr()");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String account2 = account.substring(2);
|
||||||
|
appActivity.runOnGLThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Cocos2dxJavascriptJavaBridge.evalString("window.connectOK(\""+account2+"\")");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param paramStr json str from bottom:
|
||||||
|
* * {
|
||||||
|
* chainId: "0x141",
|
||||||
|
* chainName: "KCC Mainnet",
|
||||||
|
* nativeCurrency: {
|
||||||
|
* name: "kccToken",
|
||||||
|
* symbol: "KCS",
|
||||||
|
* decimals: 18
|
||||||
|
* },
|
||||||
|
* blockExplorerUrls: ["https://explorer.kcc.io/en"],
|
||||||
|
* rpcUrls: ["https://rpc-mainnet.kcc.network"]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public static void addChain(String paramStr){
|
||||||
|
final Moshi moshi = new Moshi.Builder().build();
|
||||||
|
JsonAdapter<ChainObj> jsonAdapter = moshi.adapter(ChainObj.class);
|
||||||
|
try {
|
||||||
|
final ChainObj chainObj = jsonAdapter.fromJson(paramStr);
|
||||||
|
Log.i(TAG, chainObj.toString());
|
||||||
|
List paramList = new ArrayList<>();
|
||||||
|
paramList.add(chainObj);
|
||||||
|
Log.i(TAG, "addChain");
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
|
ExampleApplication.session.performMethodCall(new Session.MethodCall.Custom(time, "eth_signTypedData", paramList), new Function1<Session.MethodCall.Response, Unit>() {
|
||||||
|
@Override
|
||||||
|
public Unit invoke(Session.MethodCall.Response resp) {
|
||||||
|
CallResult result = new CallResult("addChain");
|
||||||
|
if (resp.getError() != null) {
|
||||||
|
Log.i(TAG, "change chain with error: " + resp.getError());
|
||||||
|
result.setErrCode(resp.getError().getCode());
|
||||||
|
result.setErrMsg(resp.getError().getMessage());
|
||||||
|
} else if (resp.getResult() != null && resp.getResult().toString().equals("success")) {
|
||||||
|
Log.i(TAG, "change chain success: " + chainObj.getChainId());
|
||||||
|
result.setErrCode(0L);
|
||||||
|
result.setErrMsg("");
|
||||||
|
result.setData(chainObj.getChainId());
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "change chain fail");
|
||||||
|
result.setErrCode(9528L);
|
||||||
|
result.setErrMsg("unknown error");
|
||||||
|
}
|
||||||
|
JsonAdapter<CallResult> resultAdapter = moshi.adapter(CallResult.class);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
|
i.setData(Uri.parse("metamask://"));
|
||||||
|
appActivity.startActivity(i);
|
||||||
|
} catch(IOException e) {
|
||||||
|
Log.i(TAG, e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,250 @@
|
|||||||
|
package org.cocos2dx.javascript.wc
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import org.bouncycastle.crypto.digests.SHA256Digest
|
||||||
|
import org.bouncycastle.crypto.engines.AESEngine
|
||||||
|
import org.bouncycastle.crypto.macs.HMac
|
||||||
|
import org.bouncycastle.crypto.modes.CBCBlockCipher
|
||||||
|
import org.bouncycastle.crypto.paddings.PKCS7Padding
|
||||||
|
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher
|
||||||
|
import org.bouncycastle.crypto.params.KeyParameter
|
||||||
|
import org.bouncycastle.crypto.params.ParametersWithIV
|
||||||
|
import org.komputing.khex.decode
|
||||||
|
import org.komputing.khex.extensions.toNoPrefixHexString
|
||||||
|
import org.walletconnect.Session
|
||||||
|
import org.walletconnect.types.*
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class JMoshiPayloadAdapter(moshi: Moshi) : Session.PayloadAdapter {
|
||||||
|
|
||||||
|
private val payloadAdapter = moshi.adapter(EncryptedPayload::class.java)
|
||||||
|
private val mapAdapter = moshi.adapter<Map<String, Any?>>(
|
||||||
|
Types.newParameterizedType(
|
||||||
|
Map::class.java,
|
||||||
|
String::class.java,
|
||||||
|
Any::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val requests: MutableMap<Long, Session.MethodCall> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
private fun createRandomBytes(i: Int) = ByteArray(i).also { SecureRandom().nextBytes(it) }
|
||||||
|
|
||||||
|
override fun parse(payload: String, key: String): Session.MethodCall {
|
||||||
|
val encryptedPayload = payloadAdapter.fromJson(payload) ?: throw IllegalArgumentException("Invalid json payload!")
|
||||||
|
|
||||||
|
// TODO verify hmac
|
||||||
|
|
||||||
|
val padding = PKCS7Padding()
|
||||||
|
val aes = PaddedBufferedBlockCipher(
|
||||||
|
CBCBlockCipher(AESEngine()),
|
||||||
|
padding
|
||||||
|
)
|
||||||
|
val ivAndKey = ParametersWithIV(
|
||||||
|
KeyParameter(decode(key)),
|
||||||
|
decode(encryptedPayload.iv)
|
||||||
|
)
|
||||||
|
aes.init(false, ivAndKey)
|
||||||
|
|
||||||
|
val encryptedData = decode(encryptedPayload.data)
|
||||||
|
val minSize = aes.getOutputSize(encryptedData.size)
|
||||||
|
val outBuf = ByteArray(minSize)
|
||||||
|
var len = aes.processBytes(encryptedData, 0, encryptedData.size, outBuf, 0)
|
||||||
|
len += aes.doFinal(outBuf, len)
|
||||||
|
|
||||||
|
return outBuf.copyOf(len).toMethodCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun prepare(data: Session.MethodCall, key: String): String {
|
||||||
|
val bytesData = data.toBytes()
|
||||||
|
val hexKey = decode(key)
|
||||||
|
val iv = createRandomBytes(16)
|
||||||
|
|
||||||
|
val padding = PKCS7Padding()
|
||||||
|
val aes = PaddedBufferedBlockCipher(
|
||||||
|
CBCBlockCipher(AESEngine()),
|
||||||
|
padding
|
||||||
|
)
|
||||||
|
aes.init(true, ParametersWithIV(KeyParameter(hexKey), iv))
|
||||||
|
|
||||||
|
val minSize = aes.getOutputSize(bytesData.size)
|
||||||
|
val outBuf = ByteArray(minSize)
|
||||||
|
val length1 = aes.processBytes(bytesData, 0, bytesData.size, outBuf, 0)
|
||||||
|
aes.doFinal(outBuf, length1)
|
||||||
|
|
||||||
|
|
||||||
|
val hmac = HMac(SHA256Digest())
|
||||||
|
hmac.init(KeyParameter(hexKey))
|
||||||
|
|
||||||
|
val hmacResult = ByteArray(hmac.macSize)
|
||||||
|
hmac.update(outBuf, 0, outBuf.size)
|
||||||
|
hmac.update(iv, 0, iv.size)
|
||||||
|
hmac.doFinal(hmacResult, 0)
|
||||||
|
requests[data.id()] = data
|
||||||
|
return payloadAdapter.toJson(
|
||||||
|
EncryptedPayload(
|
||||||
|
outBuf.toNoPrefixHexString(),
|
||||||
|
hmac = hmacResult.toNoPrefixHexString(),
|
||||||
|
iv = iv.toNoPrefixHexString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert FROM request bytes
|
||||||
|
*/
|
||||||
|
private fun ByteArray.toMethodCall(): Session.MethodCall =
|
||||||
|
String(this).let { json ->
|
||||||
|
mapAdapter.fromJson(json)?.let {
|
||||||
|
try {
|
||||||
|
var method = it["method"]
|
||||||
|
when (method) {
|
||||||
|
"wc_sessionRequest" -> it.toSessionRequest()
|
||||||
|
"wc_sessionUpdate" -> it.toSessionUpdate()
|
||||||
|
"eth_sendTransaction" -> it.toSendTransaction()
|
||||||
|
"eth_sign" -> it.toSignMessage()
|
||||||
|
null -> it.toResponse()
|
||||||
|
else -> it.toCustom()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw Session.MethodCallException.InvalidRequest(it.getId(), "$json (${e.message ?: "Unknown error"})")
|
||||||
|
}
|
||||||
|
} ?: throw IllegalArgumentException("Invalid json")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, *>.toSessionUpdate(): Session.MethodCall.SessionUpdate {
|
||||||
|
val params = this["params"] as? List<*> ?: throw IllegalArgumentException("params missing")
|
||||||
|
val data = params.firstOrNull() as? Map<String, *> ?: throw IllegalArgumentException("Invalid params")
|
||||||
|
return Session.MethodCall.SessionUpdate(
|
||||||
|
getId(),
|
||||||
|
data.extractSessionParams()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, *>.toSendTransaction(): Session.MethodCall.SendTransaction {
|
||||||
|
val params = this["params"] as? List<*> ?: throw IllegalArgumentException("params missing")
|
||||||
|
val data = params.firstOrNull() as? Map<*, *> ?: throw IllegalArgumentException("Invalid params")
|
||||||
|
val from = data["from"] as? String ?: throw IllegalArgumentException("from key missing")
|
||||||
|
val to = data["to"] as? String ?: throw IllegalArgumentException("to key missing")
|
||||||
|
val nonce = data["nonce"] as? String ?: (data["nonce"] as? Double)?.toLong()?.toString()
|
||||||
|
val gasPrice = data["gasPrice"] as? String
|
||||||
|
val gasLimit = data["gasLimit"] as? String
|
||||||
|
val value = data["value"] as? String ?: "0x0"
|
||||||
|
val txData = data["data"] as? String ?: throw IllegalArgumentException("data key missing")
|
||||||
|
return Session.MethodCall.SendTransaction(getId(), from, to, nonce, gasPrice, gasLimit, value, txData)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, *>.toSignMessage(): Session.MethodCall.SignMessage {
|
||||||
|
val params = this["params"] as? List<*> ?: throw IllegalArgumentException("params missing")
|
||||||
|
val address = params.getOrNull(0) as? String ?: throw IllegalArgumentException("Missing address")
|
||||||
|
val message = params.getOrNull(1) as? String ?: throw IllegalArgumentException("Missing message")
|
||||||
|
return Session.MethodCall.SignMessage(getId(), address, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, *>.toCustom(): Session.MethodCall.Custom {
|
||||||
|
val method = this["method"] as? String ?: throw IllegalArgumentException("method missing")
|
||||||
|
val params = this["params"] as? List<*>
|
||||||
|
return Session.MethodCall.Custom(getId(), method, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, *>.toResponse(): Session.MethodCall.Response {
|
||||||
|
var result = this["result"]
|
||||||
|
val error = this["error"] as? Map<*, *>
|
||||||
|
if (result == null && error == null) {
|
||||||
|
var hasErr = true
|
||||||
|
if (requests[getId()] != null) {
|
||||||
|
when (val localData: Session.MethodCall? = requests[getId()]) {
|
||||||
|
is Session.MethodCall.Custom -> {
|
||||||
|
if (localData.method == "wallet_switchEthereumChain" || localData.method == "wallet_addEthereumChain") {
|
||||||
|
hasErr = false
|
||||||
|
result = "success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requests.remove(getId())
|
||||||
|
}
|
||||||
|
if (hasErr) {
|
||||||
|
throw IllegalArgumentException("no result or error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Session.MethodCall.Response(
|
||||||
|
getId(),
|
||||||
|
result,
|
||||||
|
error?.extractError()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert INTO request bytes
|
||||||
|
*/
|
||||||
|
private fun Session.MethodCall.toBytes() =
|
||||||
|
mapAdapter.toJson(
|
||||||
|
when (this) {
|
||||||
|
is Session.MethodCall.SessionRequest -> this.toMap()
|
||||||
|
is Session.MethodCall.Response -> this.toMap()
|
||||||
|
is Session.MethodCall.SessionUpdate -> this.toMap()
|
||||||
|
is Session.MethodCall.SendTransaction -> this.toMap()
|
||||||
|
is Session.MethodCall.SignMessage -> this.toMap()
|
||||||
|
is Session.MethodCall.Custom -> this.toMap()
|
||||||
|
}
|
||||||
|
).toByteArray()
|
||||||
|
|
||||||
|
private fun Session.MethodCall.SessionRequest.toMap() =
|
||||||
|
jsonRpc(id, "wc_sessionRequest", peer.intoMap())
|
||||||
|
|
||||||
|
private fun Session.MethodCall.SessionUpdate.toMap() =
|
||||||
|
jsonRpc(id, "wc_sessionUpdate", params.intoMap())
|
||||||
|
|
||||||
|
private fun Session.MethodCall.SendTransaction.toMap() =
|
||||||
|
jsonRpc(
|
||||||
|
id, "eth_sendTransaction", mapOf(
|
||||||
|
"from" to from,
|
||||||
|
"to" to to,
|
||||||
|
"nonce" to nonce,
|
||||||
|
"gasPrice" to gasPrice,
|
||||||
|
"gasLimit" to gasLimit,
|
||||||
|
"value" to value,
|
||||||
|
"data" to data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Session.MethodCall.SignMessage.toMap() =
|
||||||
|
jsonRpc(
|
||||||
|
id, "eth_sign", address, message
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Session.MethodCall.Response.toMap() =
|
||||||
|
mutableMapOf<String, Any>(
|
||||||
|
"id" to id,
|
||||||
|
"jsonrpc" to "2.0"
|
||||||
|
).apply {
|
||||||
|
result?.let { this["result"] = result!! }
|
||||||
|
error?.let { this["error"] = error!!.intoMap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Session.MethodCall.Custom.toMap() =
|
||||||
|
jsonRpcWithList(
|
||||||
|
id, method, params ?: emptyList<Any>()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun jsonRpc(id: Long, method: String, vararg params: Any) =
|
||||||
|
jsonRpcWithList(id, method, params.asList())
|
||||||
|
|
||||||
|
private fun jsonRpcWithList(id: Long, method: String, params: List<*>) =
|
||||||
|
mapOf(
|
||||||
|
"id" to id,
|
||||||
|
"jsonrpc" to "2.0",
|
||||||
|
"method" to method,
|
||||||
|
"params" to params
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: @JsonClass(generateAdapter = true)
|
||||||
|
data class EncryptedPayload(
|
||||||
|
@Json(name = "data") val data: String,
|
||||||
|
@Json(name = "iv") val iv: String,
|
||||||
|
@Json(name = "hmac") val hmac: String
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,297 @@
|
|||||||
|
package org.cocos2dx.javascript.wc
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import org.walletconnect.Session
|
||||||
|
import org.walletconnect.impls.WCSessionStore
|
||||||
|
import org.walletconnect.nullOnThrow
|
||||||
|
import org.walletconnect.types.intoMap
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class JWCSession(
|
||||||
|
private val config: Session.Config,
|
||||||
|
private val payloadAdapter: Session.PayloadAdapter,
|
||||||
|
private val sessionStore: WCSessionStore,
|
||||||
|
transportBuilder: Session.Transport.Builder,
|
||||||
|
clientMeta: Session.PeerMeta,
|
||||||
|
clientId: String? = null
|
||||||
|
) : Session {
|
||||||
|
|
||||||
|
private val keyLock = Any()
|
||||||
|
|
||||||
|
// Persisted state
|
||||||
|
private var currentKey: String
|
||||||
|
|
||||||
|
private var approvedAccounts: List<String>? = null
|
||||||
|
private var chainId: Long? = null
|
||||||
|
private var handshakeId: Long? = null
|
||||||
|
private var peerId: String? = null
|
||||||
|
private var peerMeta: Session.PeerMeta? = null
|
||||||
|
|
||||||
|
private val clientData: Session.PeerData
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
private val encryptionKey: String
|
||||||
|
get() = currentKey
|
||||||
|
|
||||||
|
private val decryptionKey: String
|
||||||
|
get() = currentKey
|
||||||
|
|
||||||
|
// Non-persisted state
|
||||||
|
private val transport = transportBuilder.build(config.bridge, ::handleStatus, ::handleMessage)
|
||||||
|
private val requests: MutableMap<Long, (Session.MethodCall.Response) -> Unit> = ConcurrentHashMap()
|
||||||
|
private val sessionCallbacks: MutableSet<Session.Callback> = Collections.newSetFromMap(ConcurrentHashMap<Session.Callback, Boolean>())
|
||||||
|
|
||||||
|
init {
|
||||||
|
currentKey = config.key
|
||||||
|
clientData = sessionStore.load(config.handshakeTopic)?.let {
|
||||||
|
currentKey = it.currentKey
|
||||||
|
approvedAccounts = it.approvedAccounts
|
||||||
|
chainId = it.chainId
|
||||||
|
handshakeId = it.handshakeId
|
||||||
|
peerId = it.peerData?.id
|
||||||
|
peerMeta = it.peerData?.meta
|
||||||
|
if (clientId != null && clientId != it.clientData.id)
|
||||||
|
throw IllegalArgumentException("Provided clientId is different from stored clientId")
|
||||||
|
it.clientData
|
||||||
|
} ?: run {
|
||||||
|
Session.PeerData(clientId ?: UUID.randomUUID().toString(), clientMeta)
|
||||||
|
}
|
||||||
|
storeSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addCallback(cb: Session.Callback) {
|
||||||
|
sessionCallbacks.add(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeCallback(cb: Session.Callback) {
|
||||||
|
sessionCallbacks.remove(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearCallbacks() {
|
||||||
|
sessionCallbacks.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun propagateToCallbacks(action: Session.Callback.() -> Unit) {
|
||||||
|
sessionCallbacks.forEach {
|
||||||
|
try { it.action() }
|
||||||
|
catch (t: Throwable) {
|
||||||
|
// If error propagation fails, don't try again
|
||||||
|
nullOnThrow { it.onStatus(Session.Status.Error(t)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun peerMeta(): Session.PeerMeta? = peerMeta
|
||||||
|
|
||||||
|
override fun approvedAccounts(): List<String>? = approvedAccounts
|
||||||
|
|
||||||
|
fun chainId(): Long? = chainId
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
if (transport.connect()) {
|
||||||
|
// Register for all messages for this client
|
||||||
|
transport.send(
|
||||||
|
Session.Transport.Message(
|
||||||
|
config.handshakeTopic, "sub", ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun offer() {
|
||||||
|
if (transport.connect()) {
|
||||||
|
val requestId = createCallId()
|
||||||
|
send(Session.MethodCall.SessionRequest(requestId, clientData), topic = config.handshakeTopic, callback = { resp ->
|
||||||
|
// BUG in extractSessionParams, cast Double to Long error
|
||||||
|
(resp.result as? Map<String, *>)?.extractSessionParams()?.let { params ->
|
||||||
|
peerId = params.peerData?.id
|
||||||
|
peerMeta = params.peerData?.meta
|
||||||
|
approvedAccounts = params.accounts
|
||||||
|
chainId = params.chainId
|
||||||
|
storeSession()
|
||||||
|
propagateToCallbacks { onStatus(if (params.approved) Session.Status.Approved else Session.Status.Closed) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
handshakeId = requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun approve(accounts: List<String>, chainId: Long) {
|
||||||
|
val handshakeId = handshakeId ?: return
|
||||||
|
approvedAccounts = accounts
|
||||||
|
this.chainId = chainId
|
||||||
|
// We should not use classes in the Response, since this will not work with proguard
|
||||||
|
val params = Session.SessionParams(true, chainId, accounts, clientData).intoMap()
|
||||||
|
send(Session.MethodCall.Response(handshakeId, params))
|
||||||
|
storeSession()
|
||||||
|
propagateToCallbacks { onStatus(Session.Status.Approved) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(accounts: List<String>, chainId: Long) {
|
||||||
|
val params = Session.SessionParams(true, chainId, accounts, clientData)
|
||||||
|
send(Session.MethodCall.SessionUpdate(createCallId(), params))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reject() {
|
||||||
|
handshakeId?.let {
|
||||||
|
// We should not use classes in the Response, since this will not work with proguard
|
||||||
|
val params = Session.SessionParams(false, null, null, null).intoMap()
|
||||||
|
send(Session.MethodCall.Response(it, params))
|
||||||
|
}
|
||||||
|
endSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun approveRequest(id: Long, response: Any) {
|
||||||
|
send(Session.MethodCall.Response(id, response))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun rejectRequest(id: Long, errorCode: Long, errorMsg: String) {
|
||||||
|
send(
|
||||||
|
Session.MethodCall.Response(
|
||||||
|
id,
|
||||||
|
result = null,
|
||||||
|
error = Session.Error(errorCode, errorMsg)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun performMethodCall(call: Session.MethodCall, callback: ((Session.MethodCall.Response) -> Unit)?) {
|
||||||
|
send(call, callback = callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleStatus(status: Session.Transport.Status) {
|
||||||
|
when (status) {
|
||||||
|
Session.Transport.Status.Connected -> {
|
||||||
|
// Register for all messages for this client
|
||||||
|
transport.send(
|
||||||
|
Session.Transport.Message(
|
||||||
|
clientData.id, "sub", ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
propagateToCallbacks {
|
||||||
|
onStatus(when(status) {
|
||||||
|
Session.Transport.Status.Connected -> Session.Status.Connected
|
||||||
|
Session.Transport.Status.Disconnected -> Session.Status.Disconnected
|
||||||
|
is Session.Transport.Status.Error -> Session.Status.Error(Session.TransportError(status.throwable))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMessage(message: Session.Transport.Message) {
|
||||||
|
if (message.type != "pub") return
|
||||||
|
val data: Session.MethodCall
|
||||||
|
synchronized(keyLock) {
|
||||||
|
try {
|
||||||
|
data = payloadAdapter.parse(message.payload, decryptionKey)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
handlePayloadError(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var accountToCheck: String? = null
|
||||||
|
Log.i("JWCSession", "handle msg: $data")
|
||||||
|
when (data) {
|
||||||
|
is Session.MethodCall.SessionRequest -> {
|
||||||
|
handshakeId = data.id
|
||||||
|
peerId = data.peer.id
|
||||||
|
peerMeta = data.peer.meta
|
||||||
|
storeSession()
|
||||||
|
}
|
||||||
|
is Session.MethodCall.SessionUpdate -> {
|
||||||
|
if (!data.params.approved) {
|
||||||
|
endSession()
|
||||||
|
} else {
|
||||||
|
chainId = data.params.chainId
|
||||||
|
}
|
||||||
|
// TODO handle session update -> not important for our usecase
|
||||||
|
}
|
||||||
|
is Session.MethodCall.SendTransaction -> {
|
||||||
|
accountToCheck = data.from
|
||||||
|
}
|
||||||
|
is Session.MethodCall.SignMessage -> {
|
||||||
|
accountToCheck = data.address
|
||||||
|
}
|
||||||
|
is Session.MethodCall.Response -> {
|
||||||
|
val callback = requests[data.id] ?: return
|
||||||
|
callback(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountToCheck?.let { accountCheck(data.id(), it) } != false) {
|
||||||
|
propagateToCallbacks { onMethodCall(data) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun accountCheck(id: Long, address: String): Boolean {
|
||||||
|
approvedAccounts?.find { it.toLowerCase() == address.toLowerCase() } ?: run {
|
||||||
|
handlePayloadError(Session.MethodCallException.InvalidAccount(id, address))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlePayloadError(e: Exception) {
|
||||||
|
propagateToCallbacks { Session.Status.Error(e) }
|
||||||
|
(e as? Session.MethodCallException)?.let {
|
||||||
|
rejectRequest(it.id, it.code, it.message ?: "Unknown error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun endSession() {
|
||||||
|
sessionStore.remove(config.handshakeTopic)
|
||||||
|
approvedAccounts = null
|
||||||
|
chainId = null
|
||||||
|
internalClose()
|
||||||
|
propagateToCallbacks { onStatus(Session.Status.Closed) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeSession() {
|
||||||
|
sessionStore.store(
|
||||||
|
config.handshakeTopic,
|
||||||
|
WCSessionStore.State(
|
||||||
|
config,
|
||||||
|
clientData,
|
||||||
|
peerId?.let { Session.PeerData(it, peerMeta) },
|
||||||
|
handshakeId,
|
||||||
|
currentKey,
|
||||||
|
approvedAccounts,
|
||||||
|
chainId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if method call was handed over to transport
|
||||||
|
private fun send(
|
||||||
|
msg: Session.MethodCall,
|
||||||
|
topic: String? = peerId,
|
||||||
|
callback: ((Session.MethodCall.Response) -> Unit)? = null
|
||||||
|
): Boolean {
|
||||||
|
topic ?: return false
|
||||||
|
|
||||||
|
Log.i("JWCSession", "sendMsg: $msg.id()")
|
||||||
|
val payload: String
|
||||||
|
synchronized(keyLock) {
|
||||||
|
payload = payloadAdapter.prepare(msg, encryptionKey)
|
||||||
|
}
|
||||||
|
callback?.let {
|
||||||
|
requests[msg.id()] = callback
|
||||||
|
}
|
||||||
|
transport.send(Session.Transport.Message(topic, "pub", payload))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCallId() = System.currentTimeMillis() * 1000 + Random().nextInt(999)
|
||||||
|
|
||||||
|
private fun internalClose() {
|
||||||
|
transport.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun kill() {
|
||||||
|
val params = Session.SessionParams(false, null, null, null)
|
||||||
|
send(Session.MethodCall.SessionUpdate(createCallId(), params))
|
||||||
|
endSession()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.cocos2dx.javascript.wc
|
||||||
|
|
||||||
|
import org.walletconnect.Session
|
||||||
|
import org.walletconnect.nullOnThrow
|
||||||
|
import org.walletconnect.types.extractPeerData
|
||||||
|
import org.walletconnect.types.toStringList
|
||||||
|
|
||||||
|
|
||||||
|
fun Map<String, *>.extractSessionParams(): Session.SessionParams {
|
||||||
|
val approved = this["approved"] as? Boolean ?: throw IllegalArgumentException("approved missing")
|
||||||
|
val chainId = (this["chainId"] as? Double)?.toLong()
|
||||||
|
val accounts = nullOnThrow { (this["accounts"] as? List<*>)?.toStringList() }
|
||||||
|
|
||||||
|
return Session.SessionParams(approved, chainId, accounts, nullOnThrow { this.extractPeerData() })
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package org.cocos2dx.javascript.wc.entity;
|
||||||
|
|
||||||
|
public class CallResult {
|
||||||
|
private String type;
|
||||||
|
private long errCode;
|
||||||
|
private String errMsg;
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
public CallResult(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getErrCode() {
|
||||||
|
return errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrCode(long errCode) {
|
||||||
|
this.errCode = errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrMsg() {
|
||||||
|
return errMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrMsg(String errMsg) {
|
||||||
|
this.errMsg = errMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.cocos2dx.javascript.wc.entity;
|
||||||
|
|
||||||
|
public class ChainObj {
|
||||||
|
private String chainId;
|
||||||
|
private String chainName;
|
||||||
|
private String[] blockExplorerUrls;
|
||||||
|
private String[] rpcUrls;
|
||||||
|
private CurrencyObj nativeCurrency;
|
||||||
|
|
||||||
|
public String getChainId() {
|
||||||
|
return chainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChainId(String chainId) {
|
||||||
|
this.chainId = chainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChainName() {
|
||||||
|
return chainName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChainName(String chainName) {
|
||||||
|
this.chainName = chainName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getBlockExplorerUrls() {
|
||||||
|
return blockExplorerUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlockExplorerUrls(String[] blockExplorerUrls) {
|
||||||
|
this.blockExplorerUrls = blockExplorerUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getRpcUrls() {
|
||||||
|
return rpcUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRpcUrls(String[] rpcUrls) {
|
||||||
|
this.rpcUrls = rpcUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurrencyObj getNativeCurrency() {
|
||||||
|
return nativeCurrency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNativeCurrency(CurrencyObj nativeCurrency) {
|
||||||
|
this.nativeCurrency = nativeCurrency;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.cocos2dx.javascript.wc.entity;
|
||||||
|
|
||||||
|
public class ChangeChainObj {
|
||||||
|
private String chainId;
|
||||||
|
|
||||||
|
public String getChainId() {
|
||||||
|
return chainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChainId(String chainId) {
|
||||||
|
this.chainId = chainId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.cocos2dx.javascript.wc.entity;
|
||||||
|
|
||||||
|
public class CurrencyObj {
|
||||||
|
private String name;
|
||||||
|
private String symbol;
|
||||||
|
private long decimals;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSymbol() {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSymbol(String symbol) {
|
||||||
|
this.symbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDecimals() {
|
||||||
|
return decimals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDecimals(long decimals) {
|
||||||
|
this.decimals = decimals;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
{"packageUrl":"https://www.cebg.games/pubgv4/","remoteManifestUrl":"https://www.cebg.games/pubgv4/project.manifest","remoteVersionUrl":"https://www.cebg.games/pubgv4/version.manifest","version":"0.5.0"}
|
{"packageUrl":"https://www.cebg.games/pubgv4/","remoteManifestUrl":"https://www.cebg.games/pubgv4/project.manifest","remoteVersionUrl":"https://www.cebg.games/pubgv4/version.manifest","version":"0.6.0"}
|
Loading…
x
Reference in New Issue
Block a user