반응형

이번 포스팅에서는 키스토어의 계정을 연동해서 keystore를 이용해서 이더를 송금하는 실습을 진행해보겠습니다.

keystore를 최신으로 업데이트하여야합니다. 우선 전체 코드입니다. 

package com.example.samsungblockchainsdk;
import androidx.appcompat.app.AppCompatActivity;
import com.samsung.android.sdk.blockchain.account.Account;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.Toast;
import com.samsung.android.sdk.blockchain.CoinType;
import com.samsung.android.sdk.blockchain.ListenableFutureTask;
import com.samsung.android.sdk.blockchain.SBlockchain;
import com.samsung.android.sdk.blockchain.account.ethereum.EthereumAccount;
import com.samsung.android.sdk.blockchain.coinservice.CoinNetworkInfo;
import com.samsung.android.sdk.blockchain.coinservice.CoinServiceFactory;
import com.samsung.android.sdk.blockchain.coinservice.ethereum.EthereumService;
import com.samsung.android.sdk.blockchain.exception.HardwareWalletException;
import com.samsung.android.sdk.blockchain.exception.RootSeedChangedException;
import com.samsung.android.sdk.blockchain.network.EthereumNetworkType;
import com.samsung.android.sdk.blockchain.ui.CucumberWebView;
import com.samsung.android.sdk.blockchain.ui.OnSendTransactionListener;
import com.samsung.android.sdk.blockchain.wallet.HardwareWallet;
import com.samsung.android.sdk.blockchain.wallet.HardwareWalletType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class Main2Activity extends AppCompatActivity implements OnSendTransactionListener {
    Button connect;
    Button generateAccount;
    Button getAccounts;
    Button paymentsheet;
  //  Button sendSmartContract;
    // 웹뷰버튼
    Button webViewInitBtn;


    private SBlockchain sBlockchain ;
    private HardwareWallet wallet;
    private CucumberWebView webView; // 웹뷰 변수 선언
    Account generateAccount1;
    private List<Account> accounts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        // Blockchain SDK Init
        sBlockchain = new SBlockchain(); // Blockchain SDK Init
        try {
            sBlockchain.initialize(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 끝


        //이벤트 리스너 호출 //
        connect = findViewById(R.id.connect);
        generateAccount =  findViewById(R.id.generateAccount);
        getAccounts = findViewById(R.id.getAccounts);
        paymentsheet = findViewById(R.id.paymentsheet);
        //cucumber 이벤트 리스너 호출
        webViewInitBtn = findViewById(R.id.webviewinit); // 웹뷰버튼 객체생성
        webView = findViewById(R.id.cucumber); //큐컴버 웹뷰 객체생성

        connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"connect버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                connected();
            }
        });

        generateAccount.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"generateAccount버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                generate();
            }
        });

        getAccounts.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"getAccounts버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                setgetAccounts();

            }
        });

      paymentsheet.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Toast.makeText(getApplicationContext(),"paymentsheet버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
              setPaymentsheet();
          }
      });

      webViewInitBtn.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {

              webViewInit();
          }
      });

        //이벤트 리스너 호출  끝//
    }




    //1. connect
    public void connected(){
       sBlockchain.getHardwareWalletManager()
               .connect(HardwareWalletType.SAMSUNG,true) //하드웨어 wallet을 반환하는 형태입니다.
               .setCallback(new ListenableFutureTask.Callback<HardwareWallet>() { //비동기화  자기혼자 쓰레드로 돌아가기 위해서
                   @Override
                   public void onSuccess(HardwareWallet hardwareWallet) {
                        wallet = hardwareWallet;
                   }

                   @Override
                   public void onFailure(ExecutionException e) {
                       Throwable cause = e.getCause();

                       if (cause instanceof HardwareWalletException) {
                           // handling hardware wallet error
                       } else if (cause instanceof RootSeedChangedException) {
                           // handling root seed changed exception
                       }
                   }

                   @Override
                   public void onCancelled(InterruptedException e) {

                   }
               });
    }




    //2. generateAccount
    private  void generate() { //계정생성
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager()
                .generateNewAccount(wallet, coinNetworkInfo)
                .setCallback(new ListenableFutureTask.Callback< Account >() {
                    @Override
                    public void onSuccess(Account account) {
                        generateAccount1 = account;
                        Log.e("MyApp", account.toString());
                    }

                    @Override
                    public void onFailure(@NotNull ExecutionException e) {
                        Log.e("MyApp fail",e.toString());

                    }

                    @Override
                    public void onCancelled(@NotNull InterruptedException e) {
                        Log.e("MyApp cancel",e.toString());
                    }
                });

    }



    //3. getAccounts
    private  void setgetAccounts() { //
        accounts = sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(),CoinType.ETH, EthereumNetworkType.ROPSTEN);
        Log.d("MyApp", Arrays.toString(new List[]{accounts})); // 리스트형태로 로그메시지 출력
    }



    //4. paymentsheet
    private  void setPaymentsheet(){ //계정으로 0.01이더만큼 전송합니다.
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager() //우리 어카운트가 잇겟죠
                .getAccounts(wallet.getWalletId(),
                        CoinType.ETH,
                        EthereumNetworkType.ROPSTEN
                        );
        // 메타마스크와 삼성키스토어의 계좌번호는 서로 다르다. 규칙이 다르기 때문이다.

        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this,coinNetworkInfo);
        Intent intent = service
                .createEthereumPaymentSheetActivityIntent(
                        this,
                        wallet,
                        (EthereumAccount) accounts.get(0),
                        "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019",
                        new BigInteger("10000000000000000"),
                        null,
                        null
                );
        startActivityForResult(intent,0);


    }
    //5. 웹을 가져오는 실습
    private void webViewInit() {
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"
        );
        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this, coinNetworkInfo);

        accounts =  sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(), CoinType.ETH, EthereumNetworkType.ROPSTEN);

        webView.init(service, accounts.get(0), this);
        webView.loadUrl("https://faucet.metamask.io/");
    }

    @Override
    public void onSendTransaction(
            @NotNull String requestId,
            @NotNull EthereumAccount fromAccount,
            @NotNull String toAddress,
            @org.jetbrains.annotations.Nullable BigInteger value,
            @org.jetbrains.annotations.Nullable String data,
            @org.jetbrains.annotations.Nullable BigInteger nonce
    ) {
        HardwareWallet wallet =
                sBlockchain.getHardwareWalletManager().getConnectedHardwareWallet();

        Intent intent =
                webView.createEthereumPaymentSheetActivityIntent(
                        this,
                        requestId,
                        wallet,
                        toAddress,
                        value,
                        data,
                        nonce
                );

        startActivityForResult(intent, 0);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != 0) {
            return;
        }
        webView.onActivityResult(requestCode, resultCode, data);
    }



}

 

버튼객체선언입니다.

 Button connect;
    Button generateAccount;
    Button getAccounts;
    Button paymentsheet;
    // 웹뷰버튼
    Button webViewInitBtn;

SBlockchain은 1) samsung Blockchain SDK Init을 하고,  2) 하드웨어 wallet을 반환받고, 3) coinNetworkInfo에서 받은 네트워크 정보로 계정을 생성하는데 사용됩니다. 이후 계정에 대한 정보를 해당객체를 통해 얻어옵니다.

wallet은 메소드를 통해 하드웨어 wallet에 대한 정보를 받아와 저장하는 역할입니다. generateAccount1은 계정에 대한 정보를 받아오는 default형 객체이고 List형태로 계정들의 정보를 가져오는 accounts도 선언했습니다. (웹뷰에 관한 내용은 이더송금과는 별개이기에 생략하겠습니다.)

 private SBlockchain sBlockchain ;
    private HardwareWallet wallet;
    private CucumberWebView webView; // 웹뷰 변수 선언
    Account generateAccount1;
    private List<Account> accounts;

SBlockchain의 객체를 초기화합니다.

 // Blockchain SDK Init
        sBlockchain = new SBlockchain(); // Blockchain SDK Init
        try {
            sBlockchain.initialize(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

이벤트 리스너 호출을 위해 객체들을 생성합니다.

 //이벤트 리스너 호출 //
        connect = findViewById(R.id.connect);
        generateAccount =  findViewById(R.id.generateAccount);
        getAccounts = findViewById(R.id.getAccounts);
        paymentsheet = findViewById(R.id.paymentsheet);
        //cucumber 이벤트 리스너 호출
        webViewInitBtn = findViewById(R.id.webviewinit); // 웹뷰버튼 객체생성
        webView = findViewById(R.id.cucumber); //큐컴버 웹뷰 객체생성

이후 각각의 리스너객체에서는 toast메시지를 출력하고 각각에 해당하는 메소드들을 호출하는 구조입니다.

1. connect입니다. 하드웨어 wallet정보를 가져와서 계정과 연결하는 함수입니다. 

//1. connect
    public void connected(){
       sBlockchain.getHardwareWalletManager()
               .connect(HardwareWalletType.SAMSUNG,true) //하드웨어 wallet을 반환하는 형태입니다.
               .setCallback(new ListenableFutureTask.Callback<HardwareWallet>() { //비동기화  자기혼자 쓰레드로 돌아가기 위해서
                   @Override
                   public void onSuccess(HardwareWallet hardwareWallet) {
                        wallet = hardwareWallet;
                   }

                   @Override
                   public void onFailure(ExecutionException e) {
                       Throwable cause = e.getCause();

                       if (cause instanceof HardwareWalletException) {
                           // handling hardware wallet error
                       } else if (cause instanceof RootSeedChangedException) {
                           // handling root seed changed exception
                       }
                   }

                   @Override
                   public void onCancelled(InterruptedException e) {

                   }
               });
    }

2. 네트워크정보를 받습니다. 이때 퍼블릭노드가 필요한데, "https://ropsten.infura.io/" 에 들어가셔서 로그인 하시면 퍼블릭노드를 얻을 수 있습니다. CoinType.ETH, EthereumNetworkType.ROPSTEN로 설정합니다.

해당 네트워크정보와 wallet정보로 계정을 생성합니다. 디버그를 통해 계정의 주소를 알 수 있고 메타마스크에 추가도 할 수 있습니다. 

 

    //2. generateAccount
    private  void generate() { //계정생성
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager()
                .generateNewAccount(wallet, coinNetworkInfo)
                .setCallback(new ListenableFutureTask.Callback< Account >() {
                    @Override
                    public void onSuccess(Account account) {
                        generateAccount1 = account;
                        Log.e("MyApp", account.toString());
                    }

                    @Override
                    public void onFailure(@NotNull ExecutionException e) {
                        Log.e("MyApp fail",e.toString());

                    }

                    @Override
                    public void onCancelled(@NotNull InterruptedException e) {
                        Log.e("MyApp cancel",e.toString());
                    }
                });

    }

3. 계정들의 정보를 리스트형태로 저장하고 log에 출력하는 구문입니다. 

    //3. getAccounts
    private  void setgetAccounts() { //
        accounts = sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(),CoinType.ETH, EthereumNetworkType.ROPSTEN);
        Log.d("MyApp", Arrays.toString(new List[]{accounts})); // 리스트형태로 로그메시지 출력
    }

 

4. 결제창을 띄우는 코드입니다. 네트워크정보와 어카운트매니저를 불러오고, EthereumService의 객체를 생성해서 인텐트를 구현합니다. 라이브러리에 의해 인텐트되는 것이고 아래 "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019"는

보낼 주소 new BigInteger("10000000000000000")는 1wei단위의 이더리움을 의미합니다. 이렇게 하면 0.1이더를 보내는 형태가 될것입니다. 

 

 private  void setPaymentsheet(){ //계정으로 0.01이더만큼 전송합니다.
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager() //우리 어카운트가 잇겟죠
                .getAccounts(wallet.getWalletId(),
                        CoinType.ETH,
                        EthereumNetworkType.ROPSTEN
                        );
        // 메타마스크와 삼성키스토어의 계좌번호는 서로 다르다. 규칙이 다르기 때문이다.

        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this,coinNetworkInfo);
        Intent intent = service
                .createEthereumPaymentSheetActivityIntent(
                        this,
                        wallet,
                        (EthereumAccount) accounts.get(0),
                        "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019",
                        new BigInteger("10000000000000000"),
                        null,
                        null
                );
        startActivityForResult(intent,0);


    }

 

5. 웹뷰를 통해서 웹의 화면은 앱으로 보여주는 역할을 합니다. 어렵기도 하지만 하나의 규칙처럼 사용되기도 하고, 복잡하여서 설명을 생략하겠습니다.

 

  //5. 웹을 가져오는 실습
    private void webViewInit() {
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"
        );
        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this, coinNetworkInfo);

        accounts =  sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(), CoinType.ETH, EthereumNetworkType.ROPSTEN);

        webView.init(service, accounts.get(0), this);
        webView.loadUrl("https://faucet.metamask.io/");
    }

    @Override
    public void onSendTransaction(
            @NotNull String requestId,
            @NotNull EthereumAccount fromAccount,
            @NotNull String toAddress,
            @org.jetbrains.annotations.Nullable BigInteger value,
            @org.jetbrains.annotations.Nullable String data,
            @org.jetbrains.annotations.Nullable BigInteger nonce
    ) {
        HardwareWallet wallet =
                sBlockchain.getHardwareWalletManager().getConnectedHardwareWallet();

        Intent intent =
                webView.createEthereumPaymentSheetActivityIntent(
                        this,
                        requestId,
                        wallet,
                        toAddress,
                        value,
                        data,
                        nonce
                );

        startActivityForResult(intent, 0);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != 0) {
            return;
        }
        webView.onActivityResult(requestCode, resultCode, data);
    }

 

다음시간에는 블록체인 sdk 심화과정이 있겠습니다. 

모르시는 부분은 아래 댓글에 남겨주세요. 

반응형

'Blockchain 개발 > SAMSUNG Blockchain SDK' 카테고리의 다른 글

SAMSUNG Blockchain SDK 따라하기(1)  (0) 2020.02.10

+ Recent posts